<!DOCTYPE html>



  


<html class="theme-next gemini use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">






  
  
  <link rel="stylesheet" media="all" href="/lib/Han/dist/han.min.css?v=3.3">




<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/favicon.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon.png?v=5.1.4">


  <link rel="mask-icon" href="/images/favicon.png?v=5.1.4" color="#222">





  <meta name="keywords" content="项目," />





  <link rel="alternate" href="/atom.xml" title="平步青云win" type="application/atom+xml" />






<meta name="description" content="自学习项目，具体教程来自B站学习视频。采用FASTDFS，Redis，Mysql，FastCGI, QT，C，C++等实现一个图床！">
<meta name="keywords" content="项目">
<meta property="og:type" content="article">
<meta property="og:title" content="图床项目笔记">
<meta property="og:url" content="https://zxpgo.github.io/2019/11/18/云盘项目/index.html">
<meta property="og:site_name" content="平步青云win">
<meta property="og:description" content="自学习项目，具体教程来自B站学习视频。采用FASTDFS，Redis，Mysql，FastCGI, QT，C，C++等实现一个图床！">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/%E9%A1%B9%E7%9B%AE%E6%9E%B6%E6%9E%84%E5%9B%BE2.jpg">
<meta property="og:image" content="https://gss0.bdstatic.com/-4o3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=af11309fbb119313d34ef7e2045167b2/9345d688d43f87945890b673db1b0ef41bd53a04.jpg">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190904145854.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190904150702.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190904160251.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190904192126.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190905200156.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190905195706.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190905205805.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190905212024.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190906182544.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190906183617.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190906185737.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190906191811.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190907084755.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190907090814.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190907215754.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0.jpg">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/%E6%96%87%E4%BB%B6%E5%88%97%E8%A1%A8%E8%8E%B7%E5%8F%96.jpg">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD%20(1">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190926104335.png">
<meta property="og:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/20190926104414.png">
<meta property="og:updated_time" content="2019-11-25T14:36:04.139Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="图床项目笔记">
<meta name="twitter:description" content="自学习项目，具体教程来自B站学习视频。采用FASTDFS，Redis，Mysql，FastCGI, QT，C，C++等实现一个图床！">
<meta name="twitter:image" content="https://raw.githubusercontent.com/zxpgo/images/master/img/%E9%A1%B9%E7%9B%AE%E6%9E%B6%E6%9E%84%E5%9B%BE2.jpg">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Gemini',
    version: '5.1.4',
    sidebar: {"position":"right","display":"post","offset":10,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: 'PAO8LM7QB1',
      apiKey: '',
      indexName: 'Blog',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://zxpgo.github.io/2019/11/18/云盘项目/"/>





  <title>图床项目笔记 | 平步青云win</title>
  





  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?7a4517a3ce6d7c50203655d056f01ac3";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>




</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-right page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">平步青云win</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <h1 class="site-subtitle" itemprop="description"></h1>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-随笔">
          <a href="/sui" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-question-circle"></i> <br />
            
            随笔
          </a>
        </li>
      

      
        <li class="menu-item menu-item-search">
          
            <a href="javascript:;" class="popup-trigger">
			
          
            
              <i class="menu-item-icon fa fa-search fa-fw"></i> <br />
            
            搜索
          </a>
        </li>
      
    </ul>
  

  
    <div class="site-search">
      
  <div class="popup search-popup local-search-popup">
  <div class="local-search-header clearfix">
    <span class="search-icon">
      <i class="fa fa-search"></i>
    </span>
    <span class="popup-btn-close">
      <i class="fa fa-times-circle"></i>
    </span>
    <div class="local-search-input-wrapper">
      <input autocomplete="off"
             placeholder="搜索..." spellcheck="false"
             type="text" id="local-search-input">
    </div>
  </div>
  <div id="local-search-result"></div>
</div>



    </div>
  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://zxpgo.github.io/2019/11/18/云盘项目/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="zxp">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="平步青云win">
    </span>

    
      <header class="post-header">

        
        
          <h2 class="post-title" itemprop="name headline">图床项目笔记</h2>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2019-11-18T10:44:14+08:00">
                2019-11-18
              </time>
            

            

            
          </span>

          

          
            
          

          
          
             <span id="/2019/11/18/云盘项目/" class="leancloud_visitors" data-flag-title="图床项目笔记">
               <span class="post-meta-divider">|</span>
               <span class="post-meta-item-icon">
                 <i class="fa fa-eye"></i>
               </span>
               
                 <span class="post-meta-item-text">阅读次数&#58;</span>
               
                 <span class="leancloud-visitors-count"></span>
             </span>
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body han-init-context" itemprop="articleBody">

      
      

      
        <p>自学习项目，具体教程来自B站学习视频。采用FASTDFS，Redis，Mysql，FastCGI, QT，C，C++等实现一个图床！<a id="more"></a></p>
<h1 id="项目架构"><a href="#项目架构" class="headerlink" title="项目架构"></a>项目架构</h1><ul>
<li><p>通过浏览器/桌面客户端访问服务器</p>
<ul>
<li>c/s</li>
<li>b/s</li>
</ul>
</li>
<li><p>反向代理服务器</p>
<ul>
<li>多台web服务器-集群</li>
<li>给web服务器分配资源</li>
</ul>
</li>
<li>高并发<ul>
<li>多态web服务器</li>
</ul>
</li>
<li>nginx服务器+FastCGI<ul>
<li>nginx处理静态请求</li>
<li>动态请求需要FastCGI处理</li>
</ul>
</li>
<li>数据：mysql+redis<ul>
<li>mysql存储很少访问的数据，比如用户名和密码，只要登陆才访问</li>
<li>redis存储频繁访问的数据</li>
</ul>
</li>
<li>分布式文件系统-FastDFS<ul>
<li>上传和下载文件</li>
</ul>
</li>
</ul>
<p>项目架构图：</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/%E9%A1%B9%E7%9B%AE%E6%9E%B6%E6%9E%84%E5%9B%BE2.jpg" alt=""></p>
<h2 id="Web服务器"><a href="#Web服务器" class="headerlink" title="Web服务器"></a>Web服务器</h2><p>常见的web服务器：</p>
<ul>
<li>tomcat服务器<ul>
<li>apache组织的产品，开源的免费服务器</li>
<li>多用于java项目</li>
</ul>
</li>
<li>Apache服务器</li>
<li>weblogic服务器<ul>
<li>bea公司，收费的服务器</li>
<li>不交费，访问量受限制</li>
</ul>
</li>
<li>IIS服务器<ul>
<li>Internet Information Server</li>
<li>微软公司主推的服务器</li>
</ul>
</li>
<li>nginx<ul>
<li>小巧且高效的HTTP服务器</li>
<li>也可以做一个高效的负载均衡反向代理</li>
</ul>
</li>
</ul>
<h2 id="FASTDFS"><a href="#FASTDFS" class="headerlink" title="FASTDFS"></a>FASTDFS</h2><p>文件系统–存储数据</p>
<p>FAT32、NTFS、ext3、ext4….</p>
<p>分布式文件系统：</p>
<ul>
<li>文件系统的全部，不在同一台主机上，在很多太主机上，多个分散的文件系统组合在一起，形成一个完整的文系统。</li>
<li>分布式的文件系统基本结构</li>
</ul>
<p>FastDFS实现分布式文件系统的搭建。</p>
<h3 id="FASTDFS概述"><a href="#FASTDFS概述" class="headerlink" title="FASTDFS概述"></a>FASTDFS概述</h3><ul>
<li><p>FASTDFS是用C语言编写的一款开源的分布式文件系统。淘宝架构师–徐庆编写的。</p>
</li>
<li><p>为互联网量身定制，充分考虑了冗余备份、负载均衡、线性扩容，并注重高可用、高性能等指标</p>
</li>
<li><p>可以很容易搭建一套高性能的文件服务器提供文件下载、上传等服务。比如图片服务器。</p>
</li>
</ul>
<h3 id="FASTDFS特点"><a href="#FASTDFS特点" class="headerlink" title="FASTDFS特点"></a>FASTDFS特点</h3><ul>
<li>应用层级的文件系统</li>
<li>不能挂载和卸载，也就是不能进行mount操作</li>
</ul>
<h3 id="FASTDFS框架中三个角色"><a href="#FASTDFS框架中三个角色" class="headerlink" title="FASTDFS框架中三个角色"></a>FASTDFS框架中三个角色</h3><ul>
<li>追踪器 Tracker</li>
<li>存储节点 Storage</li>
<li>客户端 Client</li>
</ul>
<p>下图是一个FastDFS集群：</p>
<p><img src="https://gss0.bdstatic.com/-4o3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=af11309fbb119313d34ef7e2045167b2/9345d688d43f87945890b673db1b0ef41bd53a04.jpg" alt=""></p>
<p>Client和Storage主动连接Tracker。</p>
<ul>
<li>Storage主动向Tracker报告其状态信息<ul>
<li>磁盘剩余空间</li>
<li>文件同步状况</li>
<li>文件上传下载次数</li>
</ul>
</li>
<li>Storage会启动一个单独的线程来完成对一台Tracker的连接和定时报告。</li>
<li>一个组包含的Storage不是通过配置文件设定的，而是通过Tracker获取的。</li>
</ul>
<p>Web或客户端连接Tracker，获取存储节点的IP和端口，然后利用IP和端口将文件上传到存储节点。下载的时候同样首先询问Tracker，我要下载的文件存储在哪台服务器上？Tracker返回IP和端口给用户，用户在通过IP和端口从存储节点上下载文件。</p>
<p>Tracker集群：</p>
<ul>
<li>Tracker server不存在单点故障</li>
<li>Tracker server之间是相互平等关系同时提供服务</li>
<li>客户端请求Tracker server采用轮询方式，如果请求的tracker无法提供服务则换另一个tracker。</li>
</ul>
<p>Storage集群：</p>
<ul>
<li>Storage集群采用了分组存储方式，有一个或多个组构成</li>
<li>集群存储总量为集群中所有组的存储容量之和，每个组的存储容量为组内Storage容量最小的值（木桶效应，因为组内的Storage是为了做备份）。</li>
<li>一个组由一台或多台存储服务器组成，组内的Storage server之间是平等关系</li>
<li>不同组的Storage server之间不会相互通信，同组内的Storage server之间会相互连接进行文件同步，从而保证同组内每个storage上的文件完全一致的。</li>
<li>一个组的存储容量为该组内存储服务器容量最小的那个。</li>
</ul>
<p>FastDFS的扩容：</p>
<ul>
<li><p>纵向扩容</p>
<ul>
<li>数据备份</li>
<li>当前组的最大容量为存储节点最小的那个</li>
<li>所有存储节点组名必须一样</li>
</ul>
</li>
<li><p>横向扩容</p>
<ul>
<li>增加存储空间</li>
<li>添加Group组</li>
</ul>
</li>
</ul>
<h3 id="FASTDFS安装"><a href="#FASTDFS安装" class="headerlink" title="FASTDFS安装"></a>FASTDFS安装</h3><p>首先安装<strong>libfastcommon</strong>库：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">下载源码</span></span><br><span class="line">git clone https://github.com/happyfish100/libfastcommon.git</span><br><span class="line"><span class="meta">#</span><span class="bash">安装教程查看源码里面的INSTALL文件</span></span><br><span class="line">./make.sh</span><br><span class="line">./make.sh install</span><br></pre></td></tr></table></figure>
<p>安装fastdfs</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">wget https://jaist.dl.sourceforge.net/project/fastdfs/FastDFS%20Server%20Source%20Code/FastDFS%20Server%20with%20PHP%20Extension%20Source%20Code%20V5.08/FastDFS_v5.08.tar.gz</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">安装方式跟libfastcommon相同</span></span><br><span class="line">./make.sh</span><br><span class="line">./make.sh install</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">测试安装成功</span></span><br><span class="line">fdfs_test #输出版本信息表示成功</span><br></pre></td></tr></table></figure>
<h3 id="FASTDFS配置"><a href="#FASTDFS配置" class="headerlink" title="FASTDFS配置"></a>FASTDFS配置</h3><p>默认配置文件位置：<code>/etc/fdfs</code></p>
<p>主要所有的配置文件加上了一个sample，我们需要重新复制一下，重新修改配置文件。</p>
<p>Tracker配置</p>
<ul>
<li>bind_addr:当前主机的IP</li>
<li>port:绑定的端口</li>
<li>log日志目录</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">bind_addr=192.168.80.110</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> the tracker server port</span></span><br><span class="line">port=22122</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> the base path to store data and <span class="built_in">log</span> files</span></span><br><span class="line">base_path=/root/fdfs/tracker</span><br></pre></td></tr></table></figure>
<p>Storage配置</p>
<ul>
<li>group_name：存储节点所属的组</li>
<li>bind_addr：本机IP地址</li>
<li>port：端口</li>
<li>base_path存储日志的目录</li>
<li>store_path_count：数据存储目录的个数</li>
<li>store_path0：第一个具体的存储目录，store_path1以此类推</li>
<li>tracker_server：tarcker的IP和端口</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">group_name=group1</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> <span class="built_in">bind</span> an address of this host</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> empty <span class="keyword">for</span> <span class="built_in">bind</span> all addresses of this host</span></span><br><span class="line">bind_addr=192.168.80.110</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> the storage server port</span></span><br><span class="line">port=23000</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> the base path to store data and <span class="built_in">log</span> files</span></span><br><span class="line">base_path=/root/fdfs/storage</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> path(disk or mount point) count, default value is 1</span></span><br><span class="line">store_path_count=1</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> store_path<span class="comment">#, based 0, if store_path0 not exists, it's value is base_path</span></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> the paths must be exist</span></span><br><span class="line">store_path0=/root/fdfs/storage</span><br><span class="line"><span class="meta">#</span><span class="bash">store_path1=/home/yuqing/fastdfs2</span></span><br><span class="line"></span><br><span class="line">tracker_server=192.168.80.110:22122</span><br></pre></td></tr></table></figure>
<p>Client配置：</p>
<ul>
<li>log日志目录</li>
<li>tracker_server的IP和端口</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> the base path to store <span class="built_in">log</span> files</span></span><br><span class="line">base_path=/root/fdfs/client</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> tracker_server can ocur more than once, and tracker_server format is</span></span><br><span class="line"><span class="meta">#</span><span class="bash">  <span class="string">"host:port"</span>, host can be hostname or ip address</span></span><br><span class="line">tracker_server=192.168.80.110:22122</span><br></pre></td></tr></table></figure>
<h3 id="FASTDFS启动"><a href="#FASTDFS启动" class="headerlink" title="FASTDFS启动"></a>FASTDFS启动</h3><p>第一步，启动Tracker：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">fdfs_trackerd /etc/fdfs/tracker.conf</span><br><span class="line">fdfs_trackerd /etc/fdfs/tracker.conf restart  #重启</span><br><span class="line">fdfs_trackerd /etc/fdfs/tracker.conf stop     #关闭</span><br></pre></td></tr></table></figure>
<p>第二步，启动Storage</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">fdfs_storaged /etc/fdfs/storage.conf</span><br><span class="line">fdfs_storaged /etc/fdfs/storage.conf restart </span><br><span class="line">fdfs_storaged /etc/fdfs/storage.conf stop</span><br></pre></td></tr></table></figure>
<p>通过查看进程是否起来，判断以上两个命令是否运行成功：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps aux | grep fdfs*</span><br></pre></td></tr></table></figure>
<p>最后通过客户端来测试是否启动成功：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">fdfs_monitor /etc/fdfs/client.conf</span><br><span class="line"><span class="meta">#</span><span class="bash">输出信息</span></span><br><span class="line">server_count=1, server_index=0</span><br><span class="line"></span><br><span class="line">tracker server is 192.168.80.110:22122</span><br><span class="line"></span><br><span class="line">group count: 1</span><br><span class="line"></span><br><span class="line">Group 1:</span><br><span class="line">group name = group1</span><br><span class="line">disk total space = 17394 MB</span><br><span class="line">disk free space = 14491 MB</span><br><span class="line">trunk free space = 0 MB</span><br><span class="line">storage server count = 1</span><br><span class="line">active server count = 1</span><br><span class="line">storage server port = 23000</span><br><span class="line">storage HTTP port = 8888</span><br><span class="line">store path count = 1</span><br><span class="line">subdir count per path = 256</span><br><span class="line">current write server index = 0</span><br><span class="line">current trunk file id = 0</span><br><span class="line"></span><br><span class="line">	Storage 1:</span><br><span class="line">		id = 192.168.80.110</span><br><span class="line">		ip_addr = 192.168.80.110 (k8s-master)  ACTIVE  #表示启动成功</span><br><span class="line">		http domain = </span><br><span class="line">		version = 5.08</span><br><span class="line">		join time = 2019-09-04 02:28:14</span><br><span class="line">		up time = 2019-09-04 02:28:14</span><br><span class="line">		total storage = 17394 MB</span><br></pre></td></tr></table></figure>
<p>注意：所有fdfs的可执行文件都在<code>/usr/bin</code>目录下：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[root@k8s-master fdfs]# ls /usr/bin/fdfs*</span><br><span class="line">/usr/bin/fdfs_appender_test   /usr/bin/fdfs_append_file  /usr/bin/fdfs_delete_file    /usr/bin/fdfs_file_info  /usr/bin/fdfs_storaged  /usr/bin/fdfs_test1     /usr/bin/fdfs_upload_appender</span><br><span class="line">/usr/bin/fdfs_appender_test1  /usr/bin/fdfs_crc32        /usr/bin/fdfs_download_file  /usr/bin/fdfs_monitor    /usr/bin/fdfs_test      /usr/bin/fdfs_trackerd  /usr/bin/fdfs_upload_file</span><br></pre></td></tr></table></figure>
<p>上传文件测试：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">fdfs_upload_file /etc/fdfs/client.conf INSTALL  #INSTALL就是上传的文件，比如在当前目录下</span><br><span class="line"><span class="meta">#</span><span class="bash">输出id</span></span><br><span class="line">group1/M00/00/00/wKhQbl1vW3iAEpsuAAAeS70IE2U1586163 #M00对应我们设置的目录 /root/fdfs/storage</span><br><span class="line"><span class="meta">#</span><span class="bash">现在就可以在我们设置的存储路径下查看数据</span></span><br><span class="line">[root@k8s-master storage]# ls</span><br><span class="line">data  logs</span><br><span class="line">[root@k8s-master storage]# cd data</span><br><span class="line">[root@k8s-master data]# ls</span><br><span class="line">00  09  12  1B  24  2D  36  3F  48  51  5A  63  6C  75  7E  87  90  99  A2  AB  B4  BD  C6  CF  D8  E1  EA  F3  FC</span><br><span class="line">01  0A  13  1C  25  2E  37  40  49  52  5B  64  6D  76  7F  88  91  9A  A3  AC  B5  BE  C7  D0  D9  E2  EB  F4  FD</span><br><span class="line">02  0B  14  1D  26  2F  38  41  4A  53  5C  65  6E  77  80  89  92  9B  A4  AD  B6  BF  C8  D1  DA  E3  EC  F5  fdfs_storaged.pid</span><br><span class="line">03  0C  15  1E  27  30  39  42  4B  54  5D  66  6F  78  81  8A  93  9C  A5  AE  B7  C0  C9  D2  DB  E4  ED  F6  FE</span><br><span class="line">04  0D  16  1F  28  31  3A  43  4C  55  5E  67  70  79  82  8B  94  9D  A6  AF  B8  C1  CA  D3  DC  E5  EE  F7  FF</span><br><span class="line">05  0E  17  20  29  32  3B  44  4D  56  5F  68  71  7A  83  8C  95  9E  A7  B0  B9  C2  CB  D4  DD  E6  EF  F8  storage_stat.dat</span><br><span class="line">06  0F  18  21  2A  33  3C  45  4E  57  60  69  72  7B  84  8D  96  9F  A8  B1  BA  C3  CC  D5  DE  E7  F0  F9  sync</span><br><span class="line">07  10  19  22  2B  34  3D  46  4F  58  61  6A  73  7C  85  8E  97  A0  A9  B2  BB  C4  CD  D6  DF  E8  F1  FA</span><br><span class="line">08  11  1A  23  2C  35  3E  47  50  59  62  6B  74  7D  86  8F  98  A1  AA  B3  BC  C5  CE  D7  E0  E9  F2  FB</span><br><span class="line">[root@k8s-master data]# cd 00</span><br><span class="line">[root@k8s-master 00]# ls</span><br><span class="line">00  08  10  18  20  28  30  38  40  48  50  58  60  68  70  78  80  88  90  98  A0  A8  B0  B8  C0  C8  D0  D8  E0  E8  F0  F8</span><br><span class="line">01  09  11  19  21  29  31  39  41  49  51  59  61  69  71  79  81  89  91  99  A1  A9  B1  B9  C1  C9  D1  D9  E1  E9  F1  F9</span><br><span class="line">02  0A  12  1A  22  2A  32  3A  42  4A  52  5A  62  6A  72  7A  82  8A  92  9A  A2  AA  B2  BA  C2  CA  D2  DA  E2  EA  F2  FA</span><br><span class="line">03  0B  13  1B  23  2B  33  3B  43  4B  53  5B  63  6B  73  7B  83  8B  93  9B  A3  AB  B3  BB  C3  CB  D3  DB  E3  EB  F3  FB</span><br><span class="line">04  0C  14  1C  24  2C  34  3C  44  4C  54  5C  64  6C  74  7C  84  8C  94  9C  A4  AC  B4  BC  C4  CC  D4  DC  E4  EC  F4  FC</span><br><span class="line">05  0D  15  1D  25  2D  35  3D  45  4D  55  5D  65  6D  75  7D  85  8D  95  9D  A5  AD  B5  BD  C5  CD  D5  DD  E5  ED  F5  FD</span><br><span class="line">06  0E  16  1E  26  2E  36  3E  46  4E  56  5E  66  6E  76  7E  86  8E  96  9E  A6  AE  B6  BE  C6  CE  D6  DE  E6  EE  F6  FE</span><br><span class="line">07  0F  17  1F  27  2F  37  3F  47  4F  57  5F  67  6F  77  7F  87  8F  97  9F  A7  AF  B7  BF  C7  CF  D7  DF  E7  EF  F7  FF</span><br><span class="line">[root@k8s-master 00]# cd 00</span><br><span class="line">[root@k8s-master 00]# ls</span><br><span class="line">wKhQbl1vW3iAEpsuAAAeS70IE2U1586163</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">下载文件</span></span><br><span class="line">[root@k8s-master ~]# fdfs_download_file /etc/fdfs/client.conf group1/M00/00/00/wKhQbl1vW3iAEpsuAAAeS70IE2U1586163</span><br><span class="line">[root@k8s-master ~]# ls</span><br><span class="line">alloc.c  anaconda-ks.cfg  download  fdfs  wKhQbl1vW3iAEpsuAAAeS70IE2U1586163</span><br></pre></td></tr></table></figure>
<h3 id="文件上传和下载流程"><a href="#文件上传和下载流程" class="headerlink" title="文件上传和下载流程"></a>文件上传和下载流程</h3><p>文件上传：</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190904145854.png" alt=""></p>
<p>文件下载：</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190904150702.png" alt=""></p>
<p>group1/M00/00/00/wKhQbl1vW3iAEpsuAAAeS70IE2U1586163</p>
<ul>
<li>group1组名</li>
<li>M00 虚拟磁盘路径，对应store_path*=…</li>
<li>00/00 二级目录，存储文件的目录</li>
<li>wKhQbl1vW3iAEpsuAAAeS70IE2U1586163文件名</li>
</ul>
<p>文件名包含的信息：</p>
<ul>
<li>采用Base64编码</li>
<li>包含的字段：<ul>
<li>源storage server IP</li>
<li>文件创建时间</li>
<li>文件大小</li>
<li>文件CRC32校验码（循环冗余校验）</li>
<li>随机数</li>
</ul>
</li>
</ul>
<h3 id="找不到动态库-so的问题"><a href="#找不到动态库-so的问题" class="headerlink" title="找不到动态库.so的问题"></a>找不到动态库.so的问题</h3><p>第一种：</p>
<ul>
<li>使用环境变量LD_LIBRARY_PATH</li>
<li>动态库的绝对路径添加到该环境变量中</li>
<li>LD_LIBRARY_PATH=/usr/include/…:$LD_LIBRARY_PATH</li>
<li>export LD_LIBRARY_PATH<ul>
<li>直接在shell中执行 - 临时设置，重启失效</li>
<li>写入配置文件<ul>
<li>~/.bashrc -用户级别</li>
<li>/etc/prefile - 系统级别</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>第二种：</p>
<ul>
<li>给动态库设置软链接 /usr/kevin/fastdfs</li>
<li>将软链接放到/usr/lib /usr/lib64 /lib /lib64</li>
<li>sudo ln -s /usr/kevin/fastdfs/xxx.so  /usr/lib/libxxx.so</li>
</ul>
<p>第三种：</p>
<ul>
<li>刷新/etc/ld.so.cache<ul>
<li>首先 vi /etc/ld.so.conf，将动态库的绝对路径写入该文件中</li>
<li>sudo ldconfig -v</li>
</ul>
</li>
</ul>
<h3 id="代码实现FastDFS文件上传和下载"><a href="#代码实现FastDFS文件上传和下载" class="headerlink" title="代码实现FastDFS文件上传和下载"></a>代码实现FastDFS文件上传和下载</h3><p>两种方式：</p>
<ul>
<li>FastDFS API实现</li>
<li>进程方式实现</li>
</ul>
<h4 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h4><p><code>FastDFS/client</code>目录下，存放了所有有关client的文件，其中有一个<code>fdfs_upload_file.c</code>，因为每一个执行文件都会对应一个.c文件，所以<code>fdfs_upload_file</code>对应<code>fdfs_upload_file.c</code>，里面实现了文件上传的功能。具体源码如下：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* Copyright (C) 2008 Happy Fish / YuQing</span></span><br><span class="line"><span class="comment">*</span></span><br><span class="line"><span class="comment">* FastDFS may be copied only under the terms of the GNU General</span></span><br><span class="line"><span class="comment">* Public License V3, which may be found in the FastDFS source kit.</span></span><br><span class="line"><span class="comment">* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;errno.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/stat.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"fdfs_client.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"logger.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">usage</span><span class="params">(<span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">"Usage: %s &lt;config_file&gt; &lt;local_filename&gt; "</span> \</span><br><span class="line">		<span class="string">"[storage_ip:port] [store_path_index]\n"</span>, argv[<span class="number">0</span>]);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">char</span> *conf_filename;</span><br><span class="line">	<span class="keyword">char</span> *local_filename;</span><br><span class="line">	<span class="keyword">char</span> group_name[FDFS_GROUP_NAME_MAX_LEN + <span class="number">1</span>];</span><br><span class="line">	ConnectionInfo *pTrackerServer;</span><br><span class="line">	<span class="keyword">int</span> result;</span><br><span class="line">	<span class="keyword">int</span> store_path_index;</span><br><span class="line">	ConnectionInfo storageServer;</span><br><span class="line">	<span class="keyword">char</span> file_id[<span class="number">128</span>];</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (argc &lt; <span class="number">3</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		usage(argv);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	log_init();</span><br><span class="line">	g_log_context.log_level = LOG_ERR;</span><br><span class="line">	ignore_signal_pipe();</span><br><span class="line"></span><br><span class="line">	conf_filename = argv[<span class="number">1</span>];</span><br><span class="line">    <span class="comment">//通过客户端配置文件初始化一些数据</span></span><br><span class="line">	<span class="keyword">if</span> ((result=fdfs_client_init(conf_filename)) != <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="keyword">return</span> result;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//通过从配置文件中读出的数据链接tracker</span></span><br><span class="line">    <span class="comment">//通过pTrackerServer可以访问tracker</span></span><br><span class="line">	pTrackerServer = tracker_get_connection();</span><br><span class="line">	<span class="keyword">if</span> (pTrackerServer == <span class="literal">NULL</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		fdfs_client_destroy();</span><br><span class="line">		<span class="keyword">return</span> errno != <span class="number">0</span> ? errno : ECONNREFUSED;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	local_filename = argv[<span class="number">2</span>];</span><br><span class="line">	*group_name = <span class="string">'\0'</span>;</span><br><span class="line">    <span class="comment">//不需要</span></span><br><span class="line">	<span class="keyword">if</span> (argc &gt;= <span class="number">4</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="keyword">const</span> <span class="keyword">char</span> *pPort;</span><br><span class="line">		<span class="keyword">const</span> <span class="keyword">char</span> *pIpAndPort;</span><br><span class="line"></span><br><span class="line">		pIpAndPort = argv[<span class="number">3</span>];</span><br><span class="line">		pPort = <span class="built_in">strchr</span>(pIpAndPort, <span class="string">':'</span>);</span><br><span class="line">		<span class="keyword">if</span> (pPort == <span class="literal">NULL</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			fdfs_client_destroy();</span><br><span class="line">			<span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"invalid storage ip address and "</span> \</span><br><span class="line">				<span class="string">"port: %s\n"</span>, pIpAndPort);</span><br><span class="line">			usage(argv);</span><br><span class="line">			<span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">		&#125;</span><br><span class="line"></span><br><span class="line">		storageServer.sock = <span class="number">-1</span>;</span><br><span class="line">		<span class="built_in">snprintf</span>(storageServer.ip_addr, <span class="keyword">sizeof</span>(storageServer.ip_addr), \</span><br><span class="line">			 <span class="string">"%.*s"</span>, (<span class="keyword">int</span>)(pPort - pIpAndPort), pIpAndPort);</span><br><span class="line">		storageServer.port = atoi(pPort + <span class="number">1</span>);</span><br><span class="line">		<span class="keyword">if</span> (argc &gt;= <span class="number">5</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			store_path_index = atoi(argv[<span class="number">4</span>]);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="keyword">else</span></span><br><span class="line">		&#123;</span><br><span class="line">			store_path_index = <span class="number">-1</span>;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">    <span class="comment">//通过追踪器得到存储节点的信息</span></span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span> ((result=tracker_query_storage_store(pTrackerServer, \</span><br><span class="line">	                &amp;storageServer, group_name, &amp;store_path_index)) != <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		fdfs_client_destroy();</span><br><span class="line">		<span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"tracker_query_storage fail, "</span> \</span><br><span class="line">			<span class="string">"error no: %d, error info: %s\n"</span>, \</span><br><span class="line">			result, STRERROR(result));</span><br><span class="line">		<span class="keyword">return</span> result;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//上传文件</span></span><br><span class="line">	result = storage_upload_by_filename1(pTrackerServer, \</span><br><span class="line">			&amp;storageServer, store_path_index, \</span><br><span class="line">			local_filename, <span class="literal">NULL</span>, \</span><br><span class="line">			<span class="literal">NULL</span>, <span class="number">0</span>, group_name, file_id);</span><br><span class="line">	<span class="keyword">if</span> (result == <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">"%s\n"</span>, file_id);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">else</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"upload file fail, "</span> \</span><br><span class="line">			<span class="string">"error no: %d, error info: %s\n"</span>, \</span><br><span class="line">			result, STRERROR(result));</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//跟tracker端口连接</span></span><br><span class="line">	tracker_disconnect_server_ex(pTrackerServer, <span class="literal">true</span>);</span><br><span class="line">    <span class="comment">//销毁client客户端</span></span><br><span class="line">	fdfs_client_destroy();</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//修改版</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;errno.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/stat.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"fdfs_client.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"logger.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">fdfs_upload_file</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span> * conf_filename, <span class="keyword">const</span> <span class="keyword">char</span> * local_filename, <span class="keyword">char</span> * file_id)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">char</span> group_name[FDFS_GROUP_NAME_MAX_LEN + <span class="number">1</span>];</span><br><span class="line">	ConnectionInfo *pTrackerServer;</span><br><span class="line">	<span class="keyword">int</span> result;</span><br><span class="line">	<span class="keyword">int</span> store_path_index;</span><br><span class="line">	ConnectionInfo storageServer;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//通过客户端配置文件初始化一些数据</span></span><br><span class="line">	<span class="keyword">if</span> ((result=fdfs_client_init(conf_filename)) != <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="keyword">return</span> result;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//通过从配置文件中读出的数据链接tracker</span></span><br><span class="line">    <span class="comment">//通过pTrackerServer可以访问tracker</span></span><br><span class="line">	pTrackerServer = tracker_get_connection();</span><br><span class="line">	<span class="keyword">if</span> (pTrackerServer == <span class="literal">NULL</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		fdfs_client_destroy();</span><br><span class="line">		<span class="keyword">return</span> errno != <span class="number">0</span> ? errno : ECONNREFUSED;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	*group_name = <span class="string">'\0'</span>;</span><br><span class="line">    <span class="comment">//通过追踪器得到存储节点的信息</span></span><br><span class="line">	<span class="keyword">if</span> ((result=tracker_query_storage_store(pTrackerServer, \</span><br><span class="line">	                &amp;storageServer, group_name, &amp;store_path_index)) != <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		fdfs_client_destroy();</span><br><span class="line">		<span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"tracker_query_storage fail, "</span> \</span><br><span class="line">			<span class="string">"error no: %d, error info: %s\n"</span>, \</span><br><span class="line">			result, STRERROR(result));</span><br><span class="line">		<span class="keyword">return</span> result;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//上传文件</span></span><br><span class="line">	result = storage_upload_by_filename1(pTrackerServer, \</span><br><span class="line">			&amp;storageServer, store_path_index, \</span><br><span class="line">			local_filename, <span class="literal">NULL</span>, \</span><br><span class="line">			<span class="literal">NULL</span>, <span class="number">0</span>, group_name, file_id);</span><br><span class="line">	<span class="keyword">if</span> (result == <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">"%s\n"</span>, file_id);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">else</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"upload file fail, "</span> \</span><br><span class="line">			<span class="string">"error no: %d, error info: %s\n"</span>, \</span><br><span class="line">			result, STRERROR(result));</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//跟tracker端口连接</span></span><br><span class="line">	tracker_disconnect_server_ex(pTrackerServer, <span class="literal">true</span>);</span><br><span class="line">    <span class="comment">//销毁client客户端</span></span><br><span class="line">	fdfs_client_destroy();</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="进程方式实现"><a href="#进程方式实现" class="headerlink" title="进程方式实现"></a>进程方式实现</h4><p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190904160251.png" alt=""></p>
<ul>
<li>创建一个匿名管道</li>
<li>创建子线程</li>
<li>子进程中执行execlp()<ul>
<li>关闭读端</li>
<li>将读到的文件ID写入管道</li>
</ul>
</li>
<li>父进程<ul>
<li>关闭写端</li>
<li>读管道：将文件ID读到内存</li>
<li>回收子进程的PCB</li>
</ul>
</li>
</ul>
<p>父子进程始终共享的东西：</p>
<ul>
<li>文件描述符 <ul>
<li>open</li>
<li>pipe</li>
</ul>
</li>
<li>内存映射区 mmap</li>
</ul>
<h2 id="Redis"><a href="#Redis" class="headerlink" title="Redis"></a>Redis</h2><p>数据库类型：</p>
<ul>
<li>关系型数据库：SQL<ul>
<li>使用SQL语句进行操作</li>
<li>数据存储在磁盘</li>
<li>常见：MySQL, Oracle，SQLite，SQLServer</li>
</ul>
</li>
<li>非关系型数据库：noSQL<ul>
<li>不依赖SQL语句</li>
<li>数据存储在内存中</li>
<li>数据可以持久化，即将数据保存到磁盘</li>
<li>数据都是键值对</li>
<li>常用：Redis, MemCache</li>
</ul>
</li>
</ul>
<p>缓存数据库和持久数据库的搭配使用：</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190904192126.png" style="zoom:75%;"></p>
<p>第一次读取从持久化数据库读取，并将数据写入缓存数据库中。然后后面的用户读取就直接从缓存数据库读取，提高了访问的速度。</p>
<p>Redis是单线程工作模式，因为在内存中处理速度快。内部维护了一个队列，将要处理的操作放入队列中。</p>
<h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> wget http://download.redis.io/releases/redis-5.0.4.tar.gz</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> tar xzf redis-5.0.4.tar.gz</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">cd</span> redis-5.0.4</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> make</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">启动服务器</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> redis-server</span></span><br><span class="line"><span class="meta">#</span><span class="bash">还可以加上配置文件启动</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> redis-server ./redis.conf</span></span><br><span class="line"><span class="meta">#</span><span class="bash">启动客户端</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> redis-cli</span></span><br><span class="line"><span class="meta">#</span><span class="bash">如果redis.conf中修改了端口</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> redis-cli -p port</span></span><br><span class="line"><span class="meta">#</span><span class="bash">远程访问时，需要在redis.conf注释掉<span class="built_in">bind</span>，在登陆时还需要添加IP</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> redis-cli -h IP -p port</span></span><br><span class="line"><span class="meta">#</span><span class="bash">客户端测试</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash"> ping</span></span><br><span class="line"><span class="meta">#</span><span class="bash">显示PONG表示安装成功</span></span><br><span class="line"><span class="meta">#</span><span class="bash">客户端关闭服务器</span></span><br><span class="line"><span class="meta">&gt;</span><span class="bash">shutdown</span></span><br></pre></td></tr></table></figure>
<h3 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h3><p>Readis中所有的数据都是键值对。</p>
<ul>
<li>key：字符串</li>
<li>常用的数据类型：<ul>
<li>字符串类型</li>
<li>Hash类型</li>
<li>List类型：字符串数组</li>
<li>Set类型</li>
<li>SortedSet类型zset</li>
</ul>
</li>
</ul>
<p>Redis命令：<a href="http://redis.cn/commands.html#" target="_blank" rel="noopener">http://redis.cn/commands.html#</a></p>
<h4 id="string"><a href="#string" class="headerlink" title="string"></a>string</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">[root@k8s-master ~]# redis-cli</span><br><span class="line">127.0.0.1:6379&gt; SET str1 hello</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379&gt; GET str1</span><br><span class="line">"hello"</span><br><span class="line">127.0.0.1:6379&gt; SET str 123</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379&gt; get str</span><br><span class="line">"123"</span><br><span class="line">127.0.0.1:6379&gt; mset str2 123 str4 345</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379&gt; keys *</span><br><span class="line">1) "str4"</span><br><span class="line">2) "str1"</span><br><span class="line">3) "str2"</span><br><span class="line">4) "str"</span><br><span class="line">127.0.0.1:6379&gt; mget str1 str2 str4 str</span><br><span class="line">1) "hello"</span><br><span class="line">2) "123"</span><br><span class="line">3) "345"</span><br><span class="line">4) "123"</span><br><span class="line">127.0.0.1:6379&gt; incr str1</span><br><span class="line">(error) ERR value is not an integer or out of range</span><br><span class="line">127.0.0.1:6379&gt; incr str2</span><br><span class="line">(integer) 124</span><br><span class="line">127.0.0.1:6379&gt; get str2</span><br><span class="line">"124"</span><br><span class="line">127.0.0.1:6379&gt; decr str2</span><br><span class="line">(integer) 123</span><br><span class="line">127.0.0.1:6379&gt; get str2</span><br><span class="line">"123"</span><br><span class="line">127.0.0.1:6379&gt; append str1 world</span><br><span class="line">(integer) 10</span><br><span class="line">127.0.0.1:6379&gt; get str1</span><br><span class="line">"helloworld"</span><br></pre></td></tr></table></figure>
<h4 id="List类型："><a href="#List类型：" class="headerlink" title="List类型："></a>List类型：</h4><p>操作过程中，既可以按照队列操作，也快成按照栈操作</p>
<ul>
<li><p>队列：</p>
<p>队头出数据，队尾进数据</p>
<p>rpush     lpop</p>
</li>
<li><p>栈</p>
<p>只能操作栈顶</p>
<p>lpush lpop</p>
<p>或者rpush rpop</p>
</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; lpush ls1 aaa bbb ccc ddd 123</span><br><span class="line">(integer) 5</span><br><span class="line">127.0.0.1:6379&gt; lrange ls1 0 -1</span><br><span class="line">1) "123"</span><br><span class="line">2) "ddd"</span><br><span class="line">3) "ccc"</span><br><span class="line">4) "bbb"</span><br><span class="line">5) "aaa"</span><br><span class="line">127.0.0.1:6379&gt; rpush ls1 9 8 7 6</span><br><span class="line">(integer) 9</span><br><span class="line">127.0.0.1:6379&gt; lrange ls1 0 -1</span><br><span class="line">1) "123"</span><br><span class="line">2) "ddd"</span><br><span class="line">3) "ccc"</span><br><span class="line">4) "bbb"</span><br><span class="line">5) "aaa"</span><br><span class="line">6) "9"</span><br><span class="line">7) "8"</span><br><span class="line">8) "7"</span><br><span class="line">9) "6"</span><br><span class="line">127.0.0.1:6379&gt; lpop ls1</span><br><span class="line">"123"</span><br><span class="line">127.0.0.1:6379&gt; rpop ls1</span><br><span class="line">"6"</span><br><span class="line">127.0.0.1:6379&gt; llen ls1</span><br><span class="line">(integer) 7</span><br></pre></td></tr></table></figure>
<h4 id="set"><a href="#set" class="headerlink" title="set"></a>set</h4><p>集合类型，集合元素是没有顺序的，但是元素是唯一的。利用set可以就交集、并集和差集。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; sadd set1 1 2 3 4 4 5 6 7</span><br><span class="line">(integer) 7</span><br><span class="line">127.0.0.1:6379&gt; smembers set1</span><br><span class="line">1) "1"</span><br><span class="line">2) "2"</span><br><span class="line">3) "3"</span><br><span class="line">4) "4"</span><br><span class="line">5) "5"</span><br><span class="line">6) "6"</span><br><span class="line">7) "7"</span><br><span class="line">127.0.0.1:6379&gt; sadd set2 4 5 6 7 8 9 </span><br><span class="line">(integer) 6</span><br><span class="line">127.0.0.1:6379&gt; sdiff set1 set2</span><br><span class="line">1) "1"</span><br><span class="line">2) "2"</span><br><span class="line">3) "3"</span><br><span class="line">127.0.0.1:6379&gt; sdiff set2 set1</span><br><span class="line">1) "8"</span><br><span class="line">2) "9"</span><br><span class="line">127.0.0.1:6379&gt; sinter set1 set2</span><br><span class="line">1) "4"</span><br><span class="line">2) "5"</span><br><span class="line">3) "6"</span><br><span class="line">4) "7"</span><br><span class="line">127.0.0.1:6379&gt; sunion set1 set2</span><br><span class="line">1) "1"</span><br><span class="line">2) "2"</span><br><span class="line">3) "3"</span><br><span class="line">4) "4"</span><br><span class="line">5) "5"</span><br><span class="line">6) "6"</span><br><span class="line">7) "7"</span><br><span class="line">8) "8"</span><br><span class="line">9) "9"</span><br></pre></td></tr></table></figure>
<h4 id="sorted"><a href="#sorted" class="headerlink" title="sorted"></a>sorted</h4><p>集合中每一个元素都有一个分数，Sortedset会根据分数进行排序。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; zadd zset1 6 hello 1 world 8 abc</span><br><span class="line">(integer) 3</span><br><span class="line">127.0.0.1:6379&gt; zrange zset1 0 -1</span><br><span class="line">1) "world"</span><br><span class="line">2) "hello"</span><br><span class="line">3) "abc"</span><br><span class="line">127.0.0.1:6379&gt; zrange zset1 0 -1 withscores</span><br><span class="line">1) "world"</span><br><span class="line">2) "1"</span><br><span class="line">3) "hello"</span><br><span class="line">4) "6"</span><br><span class="line">5) "abc"</span><br><span class="line">6) "8"</span><br><span class="line">127.0.0.1:6379&gt; zrevrange zset1 0 -1 withscores</span><br><span class="line">1) "abc"</span><br><span class="line">2) "8"</span><br><span class="line">3) "hello"</span><br><span class="line">4) "6"</span><br><span class="line">5) "world"</span><br><span class="line">6) "1"</span><br></pre></td></tr></table></figure>
<h4 id="hash"><a href="#hash" class="headerlink" title="hash"></a>hash</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">key		 value </span><br><span class="line">string	  key: value</span><br><span class="line">		  key: vlue</span><br><span class="line"><span class="meta">#</span><span class="bash">测试</span></span><br><span class="line">127.0.0.1:6379&gt; hset user usrname 张3</span><br><span class="line">(integer) 1</span><br><span class="line">127.0.0.1:6379&gt; hset user age 18</span><br><span class="line">(integer) 1</span><br><span class="line">127.0.0.1:6379&gt; hset user passwd 123456</span><br><span class="line">(integer) 1</span><br><span class="line">127.0.0.1:6379&gt; hget user usrname</span><br><span class="line">"\xe5\xbc\xa03"</span><br><span class="line">127.0.0.1:6379&gt; hget user age</span><br><span class="line">"18"</span><br><span class="line">127.0.0.1:6379&gt; hmset zhang3 sex man age 18 disp gay</span><br><span class="line">OK</span><br><span class="line">127.0.0.1:6379&gt; hmget zhang3 sex age disp</span><br><span class="line">1) "man"</span><br><span class="line">2) "18"</span><br><span class="line">3) "gay"</span><br></pre></td></tr></table></figure>
<p><code>hgetall key</code>能够获取所有的键值对</p>
<h4 id="对于key的操作"><a href="#对于key的操作" class="headerlink" title="对于key的操作"></a>对于key的操作</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1:6379&gt; keys *</span><br><span class="line"> 1) "set1"</span><br><span class="line"> 2) "str2"</span><br><span class="line"> 3) "zset1"</span><br><span class="line"> 4) "set2"</span><br><span class="line"> 5) "str"</span><br><span class="line"> 6) "ls1"</span><br><span class="line"> 7) "user"</span><br><span class="line"> 8) "zhang3"</span><br><span class="line"> 9) "str4"</span><br><span class="line">10) "str1"</span><br><span class="line">127.0.0.1:6379&gt; keys str*</span><br><span class="line">1) "str2"</span><br><span class="line">2) "str"</span><br><span class="line">3) "str4"</span><br><span class="line">4) "str1"</span><br><span class="line"><span class="meta">#</span><span class="bash">key的生存时间</span></span><br><span class="line">127.0.0.1:6379&gt; expire str1 60</span><br><span class="line">(integer) 1</span><br><span class="line">127.0.0.1:6379&gt; TTL str1</span><br><span class="line">(integer) 35</span><br><span class="line">127.0.0.1:6379&gt; TTL str1</span><br><span class="line">(integer) -2</span><br><span class="line"><span class="meta">#</span><span class="bash">清空生成时间</span></span><br><span class="line">127.0.0.1:6379&gt; persist str1</span><br><span class="line">(integer) 0</span><br><span class="line"><span class="meta">#</span><span class="bash">设置时间为毫秒，默认为秒</span></span><br><span class="line">127.0.0.1:6379&gt; pexpire str1 60</span><br><span class="line">(integer) 0</span><br><span class="line">127.0.0.1:6379&gt; TTL str1</span><br><span class="line">(integer) -2</span><br><span class="line">127.0.0.1:6379&gt; del set2</span><br><span class="line">(integer) 1</span><br><span class="line">127.0.0.1:6379&gt; keys *</span><br><span class="line">1) "set1"</span><br><span class="line">2) "str2"</span><br><span class="line">3) "zset1"</span><br><span class="line">4) "str"</span><br><span class="line">5) "ls1"</span><br><span class="line">6) "user"</span><br><span class="line">7) "zhang3"</span><br><span class="line">8) "str4"</span><br><span class="line">127.0.0.1:6379&gt; rename str4 str3</span><br><span class="line">OK</span><br></pre></td></tr></table></figure>
<p><code>type key</code>获取key的类型。</p>
<h3 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h3><p>如果远程连接，需要将修改配置文件：</p>
<ul>
<li>注释bind</li>
<li>protected-mode改为no</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"><span class="built_in">bind</span> 127.0.0.1</span></span><br><span class="line">protected-mode no #远程访问设置为no</span><br><span class="line">daemonize yes   #是否为守护，默认为no不是守护进程，修改为yes,如果是守护进程会生成一个redis.pid文件存储该进程的PID</span><br><span class="line">pidfile ./redis.pid #pid存储目录，修改后为输入命令所在的目录</span><br><span class="line">logfile "./redis.log"  #默认为/dev/null，相当于放进垃圾桶</span><br><span class="line">databases 16 #redis默认有16个数据库  使用setlect 0选择第一个数据库</span><br></pre></td></tr></table></figure>
<p>如果使用配置文件启动redis服务端，需要将配置文件拷贝到当前目录下，然后在启动命令后面加上配置文件：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis-server ./redis.conf</span><br></pre></td></tr></table></figure>
<p>如果端口换了：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis-cli -p 6380</span><br></pre></td></tr></table></figure>
<p>远程访问：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis-cli -h 192.168.80.110 -p 6380 #端口更改后的</span><br></pre></td></tr></table></figure>
<h3 id="数据持久化"><a href="#数据持久化" class="headerlink" title="数据持久化"></a>数据持久化</h3><p>redis两种持久化方式：</p>
<ul>
<li>rdb形式：默认方式<ul>
<li>特点：快照的方式，存储的是内存中的数据；按照某种频率存储数据</li>
<li>缺点：存储的频率太高，存储效率低；频率太低，同步不及时</li>
<li>优点：数据恢复要快一些</li>
</ul>
</li>
<li>Aof形式<ul>
<li>特点：存储的是命令</li>
<li>缺点：数据恢复时间长(读取命令，还要执行命令)</li>
<li>优点：</li>
</ul>
</li>
</ul>
<p>以上持久化设置都可以在配置文件完成。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">save 900 1            #900秒内至少有一个key改变，就保存</span><br><span class="line">save 300 10	          #300秒内至少10个改变，就保存</span><br><span class="line">save 60 10000</span><br></pre></td></tr></table></figure>
<p>修改存储形式：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">rdbcompression yes         </span><br><span class="line">appendonly no  #二选一</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> The name of the append only file (default: <span class="string">"appendonly.aof"</span>)</span></span><br><span class="line">appendfilename "appendonly.aof"</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> appendfsync always</span></span><br><span class="line">appendfsync everysec  #更新频率</span><br><span class="line"><span class="meta">#</span><span class="bash"> appendfsync no</span></span><br></pre></td></tr></table></figure>
<h3 id="hiredis-API接口使用"><a href="#hiredis-API接口使用" class="headerlink" title="hiredis API接口使用"></a>hiredis API接口使用</h3><h4 id="安装-1"><a href="#安装-1" class="headerlink" title="安装"></a>安装</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">下载源码</span></span><br><span class="line">git clone https://github.com/redis/hiredis.git</span><br><span class="line"><span class="meta">#</span><span class="bash">进入对应的目录</span></span><br><span class="line">cd hiredis</span><br><span class="line"><span class="meta">#</span><span class="bash">编译</span></span><br><span class="line">make</span><br><span class="line"><span class="meta">#</span><span class="bash">安装</span></span><br><span class="line">make install</span><br></pre></td></tr></table></figure>
<p>所有的接口都在源码的<code>hiredis.h</code>文件中，在examples文件夹下有使用的例子，主要看<code>examples.c</code>就可以。还有在qt里面如何使用等等。</p>
<h4 id="连接数据库"><a href="#连接数据库" class="headerlink" title="连接数据库"></a>连接数据库</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">redisContext* <span class="title">redisConnect</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* ip, <span class="keyword">int</span> port)</span></span>;</span><br></pre></td></tr></table></figure>
<ul>
<li>参数<ul>
<li>IP</li>
<li>端口</li>
</ul>
</li>
</ul>
<p>redisContext结构体：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">redisContext</span> &#123;</span></span><br><span class="line">    <span class="keyword">int</span> err; <span class="comment">/* Error flags, 0 when there is no error */</span></span><br><span class="line">    <span class="keyword">char</span> errstr[<span class="number">128</span>]; <span class="comment">/* String representation of error when applicable */</span></span><br><span class="line">    redisFD fd; <span class="comment">//文件描述符</span></span><br><span class="line">    <span class="keyword">int</span> flags;   </span><br><span class="line">    <span class="keyword">char</span> *obuf; <span class="comment">/* Write buffer */</span></span><br><span class="line">    redisReader *reader; <span class="comment">/* Protocol reader */</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">enum</span> redisConnectionType connection_type;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">timeval</span> *<span class="title">timeout</span>;</span></span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">        <span class="keyword">char</span> *host;            </span><br><span class="line">        <span class="keyword">char</span> *source_addr;</span><br><span class="line">        <span class="keyword">int</span> port;</span><br><span class="line">    &#125; tcp;               <span class="comment">//套接字通信</span></span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">        <span class="keyword">char</span> *path;</span><br><span class="line">    &#125; unix_sock;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* For non-blocking connect */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">sockadr</span> *<span class="title">saddr</span>;</span></span><br><span class="line">    <span class="keyword">size_t</span> addrlen;</span><br><span class="line">    <span class="comment">/* For SSL communication */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">redisSsl</span> *<span class="title">ssl</span>;</span></span><br><span class="line"></span><br><span class="line">&#125; redisContext;</span><br></pre></td></tr></table></figure>
<h4 id="发送请求命令"><a href="#发送请求命令" class="headerlink" title="发送请求命令"></a>发送请求命令</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span>* <span class="title">redisCommand</span><span class="params">(redisContext* c, <span class="keyword">const</span> <span class="keyword">char</span> * format, ...)</span></span>;</span><br></pre></td></tr></table></figure>
<p>返回值：</p>
<ul>
<li>返回值是一个void类型的指针，实际上指向一个redisReply类型的指针。</li>
</ul>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> <span class="title">redisReply</span> &#123;</span></span><br><span class="line">    <span class="keyword">int</span> type; <span class="comment">/* REDIS_REPLY_,执行结果返回的类型* */</span></span><br><span class="line">    <span class="keyword">long</span> <span class="keyword">long</span> integer; <span class="comment">/* The integer when type is REDIS_REPLY_INTEGER */</span></span><br><span class="line">    <span class="keyword">double</span> dval; <span class="comment">/* The double when type is REDIS_REPLY_DOUBLE */</span></span><br><span class="line">    <span class="keyword">size_t</span> len; <span class="comment">/* Length of string */</span></span><br><span class="line">    <span class="keyword">char</span> *str; <span class="comment">/* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING</span></span><br><span class="line"><span class="comment">                  and REDIS_REPLY_DOUBLE (in additionl to dval). */</span></span><br><span class="line">    <span class="keyword">size_t</span> elements; <span class="comment">/* number of elements, for REDIS_REPLY_ARRAY */</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">redisReply</span> **<span class="title">element</span>;</span> <span class="comment">/* elements vector for REDIS_REPLY_ARRAY */</span></span><br><span class="line">&#125; redisReply;</span><br></pre></td></tr></table></figure>
<p>返回的类型包括：</p>
<ul>
<li><p>REDIS_REPLY_INTEGER</p>
</li>
<li><p>REDIS_REPLY_STRING</p>
</li>
<li><p>REDIS_REPLY_ARRAY</p>
</li>
<li><p>REDIS_REPLY_ERROR</p>
</li>
</ul>
<p>对于返回类型为数组时，处理方式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">reply = redisCommand(c,<span class="string">"LRANGE mylist 0 -1"</span>);</span><br><span class="line"><span class="keyword">if</span> (reply-&gt;type == REDIS_REPLY_ARRAY) &#123;</span><br><span class="line">    <span class="keyword">for</span> (j = <span class="number">0</span>; j &lt; reply-&gt;elements; j++) &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"%u) %s\n"</span>, j, reply-&gt;element[j]-&gt;str);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">freeReplyObject(reply);</span><br></pre></td></tr></table></figure>
<h4 id="释放资源"><a href="#释放资源" class="headerlink" title="释放资源"></a>释放资源</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">freeReplyObject</span><span class="params">(<span class="keyword">void</span> * reply)</span></span>;  <span class="comment">//用来释放分配的资源</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">redisFree</span><span class="params">(redisContext * c)</span></span>;  <span class="comment">//用来释放分配的资源</span></span><br></pre></td></tr></table></figure>
<h2 id="Mysql"><a href="#Mysql" class="headerlink" title="Mysql"></a>Mysql</h2><p>安装教程：<a href="https://blog.csdn.net/pengjunlee/article/details/81212250" target="_blank" rel="noopener">https://blog.csdn.net/pengjunlee/article/details/81212250</a></p>
<p>设置远程访问：<a href="https://www.cnblogs.com/weifeng1463/p/7941625.html" target="_blank" rel="noopener">https://www.cnblogs.com/weifeng1463/p/7941625.html</a></p>
<h3 id="设置默认编码"><a href="#设置默认编码" class="headerlink" title="设置默认编码"></a>设置默认编码</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">&gt;\s #查看编码信息</span><br><span class="line">mysql&gt; \s</span><br><span class="line">--------------</span><br><span class="line">mysql  Ver 14.14 Distrib 5.6.45, for Linux (x86_64) using  EditLine wrapper</span><br><span class="line"></span><br><span class="line">Connection id:		3</span><br><span class="line">Current database:	mysql</span><br><span class="line">Current user:		root@localhost</span><br><span class="line">SSL:			Not in use</span><br><span class="line">Current pager:		stdout</span><br><span class="line">Using outfile:		&apos;&apos;</span><br><span class="line">Using delimiter:	;</span><br><span class="line">Server version:		5.6.45 MySQL Community Server (GPL)</span><br><span class="line">Protocol version:	10</span><br><span class="line">Connection:		Localhost via UNIX socket</span><br><span class="line">Server characterset:	latin1  #需要修改为utf8</span><br><span class="line">Db     characterset:	latin1  #需要修改为utf8</span><br><span class="line">Client characterset:	utf8</span><br><span class="line">Conn.  characterset:	utf8</span><br><span class="line">UNIX socket:		/var/lib/mysql/mysql.sock</span><br><span class="line">Uptime:			13 min 25 sec</span><br><span class="line"></span><br><span class="line">Threads: 4  Questions: 56  Slow queries: 0  Opens: 87  Flush tables: 1  Open tables: 80  Queries per second avg: 0.069</span><br><span class="line">--------------</span><br></pre></td></tr></table></figure>
<p>centos7下如何修改默认编码：</p>
<ul>
<li><p>进入配置文件修改配置内容，执行命令：<code>vi /etc/my.cnf</code></p>
</li>
<li><p>修改配置文件的内容，在[mysqld]结束位置添加：<code>character_set_server=utf8</code></p>
</li>
<li>重启mysql服务：<code>systemctl restart mysql</code></li>
</ul>
<h3 id="设置字段名大小写不敏感"><a href="#设置字段名大小写不敏感" class="headerlink" title="设置字段名大小写不敏感"></a>设置字段名大小写不敏感</h3><ul>
<li><p>进入配置文件修改配置内容，执行命令：<code>vi /etc/my.cnf</code></p>
</li>
<li><p>修改配置文件的内容，在[mysqld]结束位置添加：<code>lower_case_table_names=1</code></p>
</li>
<li>重启mysql服务：<code>systemctl restart mysql</code></li>
</ul>
<h2 id="Shell脚本"><a href="#Shell脚本" class="headerlink" title="Shell脚本"></a>Shell脚本</h2><p>后缀一般为.sh。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">!/bin/bash  </span></span><br><span class="line"><span class="meta">#</span><span class="bash">第一行不是注释，而是指定解析shell的命令解析器</span></span><br><span class="line">ls -l</span><br><span class="line">echo "hello world"</span><br></pre></td></tr></table></figure>
<p>添加执行权限：<code>chmod u+x hello.sh</code></p>
<p>执行脚本：<code>./hello.sh</code></p>
<p>条件判断：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">if [ 判断语句 ]; then</span><br><span class="line">	xxx</span><br><span class="line">elif [ 判断语句 ]; then</span><br><span class="line">	xxx</span><br><span class="line">else</span><br><span class="line">	xxx</span><br><span class="line">fi</span><br><span class="line"><span class="meta">#</span><span class="bash"><span class="keyword">if</span>和中括号中间有一个空格</span></span><br><span class="line"><span class="meta">#</span><span class="bash">中括号内判断语句前后必须有一个空格</span></span><br></pre></td></tr></table></figure>
<h3 id="特殊变量"><a href="#特殊变量" class="headerlink" title="特殊变量"></a>特殊变量</h3><p>$#: shell执行的时候，传递的参数个数，<code>./xxxsh aa bb cc dd</code>，一共四个参数。</p>
<p>$? : 上一条shell命令执行完成之后的返回值</p>
<p>$@: 所有的参数</p>
<p>$*: 所有的参数</p>
<p>$1: 表示第一个参数，依此类推</p>
<h3 id="变量"><a href="#变量" class="headerlink" title="变量"></a>变量</h3><ul>
<li>变量的定义</li>
</ul>
<p><code>var=&quot;hello&quot;</code></p>
<p>变量的值默认是字符串类型</p>
<p>变量名建议大写</p>
<ul>
<li>赋值：</li>
</ul>
<p><code>var=10</code>等于前后不能有空格</p>
<p>如果有空格，就是判断是否等于10。</p>
<ul>
<li>删除变量：-</li>
</ul>
<p>​    <code>unset var</code></p>
<ul>
<li><p>将命令执行之后的值赋给变量：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">方法一：使用反单引号</span></span><br><span class="line">[root@k8s-node1 html]# var=`date`</span><br><span class="line">[root@k8s-node1 html]# echo $var</span><br><span class="line">Thu Sep 5 22:24:10 EDT 2019</span><br><span class="line"><span class="meta">#</span><span class="bash">方法二：date是一个命令，所以加上()</span></span><br><span class="line">[root@k8s-node1 html]# var=$(date)</span><br><span class="line">[root@k8s-node1 html]# echo $var</span><br><span class="line">Thu Sep 5 22:25:50 EDT 2019</span><br></pre></td></tr></table></figure>
</li>
<li><p>算数运算符</p>
<p>变量先取值，在运算，取值方式有两种</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">[root@k8s-node1 html]# var=3</span><br><span class="line">[root@k8s-node1 html]# var=$[$var+3]</span><br><span class="line">[root@k8s-node1 html]# echo $var</span><br><span class="line">6</span><br><span class="line">[root@k8s-node1 html]# var=$(($var+3))</span><br><span class="line">[root@k8s-node1 html]# echo $var</span><br><span class="line">9</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="Nginx"><a href="#Nginx" class="headerlink" title="Nginx"></a>Nginx</h2><p>nginx只能处理静态网页。</p>
<h3 id="nginx介绍"><a href="#nginx介绍" class="headerlink" title="nginx介绍"></a>nginx介绍</h3><p>nginx的全称是engine x，由俄罗斯人开发的。nginx可以实现的功能：</p>
<ul>
<li>http服务器：能处理http协议的软件</li>
<li>反向代理服务器</li>
<li>邮件服务器<ul>
<li>IMAP/POP3/SMTP</li>
</ul>
</li>
</ul>
<p>nginx的优势：</p>
<ul>
<li>速度更快：高峰期nginx可以比其他web服务器更快的响应请求</li>
<li>高扩展：低耦合设计的模块组成，丰富的第三方模块支持</li>
<li>高可靠：经过大批网站检验，每个worker进程相对独立，出错之后可以快速开启新的worker</li>
<li>低内存消耗：一般情况下，10000个非活跃的HTTP Keep-Alive连接在nginx中仅消耗2.5M内存</li>
<li>单机支持10万以上的并发连接，取决于内存，10万远不封顶</li>
<li>热部署：master和worker的分离设计，可实现24小时不间断服务器的前提下审计nginx可执行文件</li>
<li>最自由的BSD许可协议：BSD许可协议允许用户免费使用nginx，修改nginx源码，然后再发布</li>
</ul>
<h3 id="正向代理和反向代理"><a href="#正向代理和反向代理" class="headerlink" title="正向代理和反向代理"></a>正向代理和反向代理</h3><h4 id="正向代理："><a href="#正向代理：" class="headerlink" title="正向代理："></a>正向代理：</h4><p>代理内部网络对Internet的连接请求</p>
<p>客户机必须指定代理服务器。</p>
<p>比如VPN，就是正向代理，正向代理服务器是为<strong>客户端服务的</strong>。</p>
<h4 id="反向代理"><a href="#反向代理" class="headerlink" title="反向代理"></a>反向代理</h4><p>反向代理服务器是为<strong>服务器服务的</strong>。</p>
<p>二者的区别：</p>
<ul>
<li>正向代理<ul>
<li>典型用途是为防止墙的局域网客户端提供访问Internet的途径</li>
<li>正向代理还可以使用缓冲特性减少网络使用率</li>
</ul>
</li>
</ul>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190905200156.png" alt=""></p>
<ul>
<li>反向代理<ul>
<li>典型用途是将防火墙后面的服务器提供给Internet用户访问</li>
<li>反向代理还可以为后端的多台服务器提供负载均衡，或为后端较慢的服务器提供缓冲服务。</li>
</ul>
</li>
</ul>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190905195706.png" alt=""></p>
<h3 id="安装-2"><a href="#安装-2" class="headerlink" title="安装"></a>安装</h3><p>Nginx相关依赖：</p>
<ul>
<li>OpenSSL: 数据加密</li>
<li>PCRE：解析正则表达式</li>
<li>ZLib：压缩和解压缩，http传输的数据都会进行压缩</li>
</ul>
<p>nginx下载地址：<a href="http://nginx.org/en/download.html" target="_blank" rel="noopener">http://nginx.org/en/download.html</a></p>
<p>openssl下载地址：<a href="https://www.openssl.org/source/old/" target="_blank" rel="noopener">https://www.openssl.org/source/old/</a></p>
<p>PCRE下载地址：<a href="https://sourceforge.net/projects/pcre/" target="_blank" rel="noopener">https://sourceforge.net/projects/pcre/</a></p>
<p>ZLib下载地址：<a href="http://www.zlib.net/" target="_blank" rel="noopener">http://www.zlib.net/</a></p>
<p>openssl安装：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">下载包</span></span><br><span class="line">wget https://www.openssl.org/source/old/1.0.1/openssl-1.0.1u.tar.gz #下载包</span><br><span class="line"><span class="meta">#</span><span class="bash">解压</span></span><br><span class="line">tar -xzvf openssl-1.0.1u.tar.gz</span><br><span class="line">cd openssl-1.0.1u</span><br><span class="line"><span class="meta">#</span><span class="bash">生成一个Makefile</span></span><br><span class="line">./config </span><br><span class="line">make #时间较长</span><br><span class="line">make install</span><br></pre></td></tr></table></figure>
<p>安装PCRE:</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">下载包</span></span><br><span class="line">wget https://jaist.dl.sourceforge.net/project/pcre/pcre/8.40/pcre-8.40.tar.gz</span><br><span class="line"><span class="meta">#</span><span class="bash">解压</span></span><br><span class="line">tar -xzvf pcre-8.40.tar.gz</span><br><span class="line"><span class="meta">#</span><span class="bash">可能需要安装gcc-c++</span></span><br><span class="line">yum -y install gcc-c++</span><br><span class="line">cd pcre-8.40</span><br><span class="line"><span class="meta">#</span><span class="bash">安装</span></span><br><span class="line"><span class="meta">#</span><span class="bash">生成Makefile</span></span><br><span class="line">./configure</span><br><span class="line">make install</span><br></pre></td></tr></table></figure>
<p>安装ZLib</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">下载包</span></span><br><span class="line">wget http://www.zlib.net/zlib-1.2.11.tar.gz</span><br><span class="line"><span class="meta">#</span><span class="bash">解压</span></span><br><span class="line">tar -xzvf zlib-1.2.11.tar.gz</span><br><span class="line">cd zlib-1.2.11</span><br><span class="line"><span class="meta">#</span><span class="bash">安装</span></span><br><span class="line"><span class="meta">#</span><span class="bash">生成Makefile</span></span><br><span class="line">./configure</span><br><span class="line">make install</span><br></pre></td></tr></table></figure>
<p>安装nginx:</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">下载包</span></span><br><span class="line"> wget http://nginx.org/download/nginx-1.10.1.tar.gz</span><br><span class="line"><span class="meta">#</span><span class="bash">解压</span></span><br><span class="line">tar -xzvf nginx-1.10.1.tar.gz</span><br><span class="line">cd nginx-1.10.1</span><br><span class="line"><span class="meta">#</span><span class="bash">安装</span></span><br><span class="line"><span class="meta">#</span><span class="bash">生成Makefile</span></span><br><span class="line">./configure</span><br><span class="line">make install</span><br></pre></td></tr></table></figure>
<p>默认安装陌路：<code>/usr/local/nginx</code></p>
<p>nginx配置文件目录：<code>/usr/local/nginx/conf</code></p>
<p>nginx log目录：<code>/usr/local/nginx/logs</code></p>
<p>静态网页存放位置：<code>/usr/local/nginx/html</code>，放入静态文件后还需要配置，后面介绍。</p>
<p>超级用户可执行程序所在位置：<code>/usr/local/nginx/sbin</code></p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">sudo ./usr/local/nginx/sbin/nginx</span><br><span class="line">ps aux | grep nginx</span><br><span class="line"><span class="meta">#</span><span class="bash">会看到启动两个进程，一个master，一个worker；master是一个管理者，worker是用来干活的</span></span><br><span class="line">root      61733  0.0  0.0  20508   600 ?        Ss   08:49   0:00 nginx: master process ./nginx</span><br><span class="line">nobody    61734  0.0  0.1  20928  1044 ?        S    08:49   0:00 nginx: worker process</span><br></pre></td></tr></table></figure>
<p>现在可以通过IP进行访问。</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190905205805.png" alt=""></p>
<p>如果修改了配置文件，就需要nginx重新加载配置文件：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./nginx -s reload</span><br></pre></td></tr></table></figure>
<p>默认监听80端口，所以访问是不需要加端口。</p>
<h3 id="nginx相关操作命令"><a href="#nginx相关操作命令" class="headerlink" title="nginx相关操作命令"></a>nginx相关操作命令</h3><p>将nginx可执行程序创建软链接放到/bin或/usr/bin 或/usr/local/bin：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx</span><br></pre></td></tr></table></figure>
<p>现在就可以直接输入<code>nginx</code>来启动nginx服务。</p>
<p>关闭nginx：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nginx -s stop</span><br></pre></td></tr></table></figure>
<p>上述命令比较粗暴，不管nginx是否工作做什么事，直接关闭。</p>
<p>下面的命令，则会等待nginx工作完毕才关闭：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nginx -s quit</span><br></pre></td></tr></table></figure>
<p>热部署：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nginx -s reload  #重新加载配置文件</span><br></pre></td></tr></table></figure>
<p>修改配置文件不需要重新启动。</p>
<h3 id="配置文件-1"><a href="#配置文件-1" class="headerlink" title="配置文件"></a>配置文件</h3><p>在conf/nginx.conf</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">user  nobody;</span></span><br><span class="line">worker_processes  1;  #work进程数量</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">error_log  logs/error.log;</span></span><br><span class="line"><span class="meta">#</span><span class="bash">error_log  logs/error.log  notice;</span></span><br><span class="line"><span class="meta">#</span><span class="bash">error_log  logs/error.log  info;</span></span><br><span class="line"><span class="meta">#</span><span class="bash">pid        logs/nginx.pid;</span></span><br><span class="line"></span><br><span class="line">events &#123;</span><br><span class="line"><span class="meta">	#</span><span class="bash">use epoll; <span class="comment">#处理高并发      </span></span></span><br><span class="line">    worker_connections  1024; #work连接的最大个数</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">http &#123;</span><br><span class="line">    include       mime.types;</span><br><span class="line">    default_type  application/octet-stream;</span><br><span class="line"></span><br><span class="line">    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '</span><br><span class="line">    #                  '$status $body_bytes_sent "$http_referer" '</span><br><span class="line">    #                  '"$http_user_agent" "$http_x_forwarded_for"';</span><br><span class="line">    #access_log  logs/access.log  main;</span><br><span class="line">    sendfile        on;</span><br><span class="line">    #tcp_nopush     on;</span><br><span class="line">    #keepalive_timeout  0;</span><br><span class="line">    keepalive_timeout  65;</span><br><span class="line">    #gzip  on;</span><br><span class="line">    server &#123;</span><br><span class="line">        listen       80;         #端口</span><br><span class="line">        server_name  localhost;  #域名，不能写IP</span><br><span class="line"></span><br><span class="line">        #charset koi8-r;</span><br><span class="line">        #access_log  logs/host.access.log  main;</span><br><span class="line">        location / &#123;      #浏览器请求的指令</span><br><span class="line">            root   html;          #静态资源根目录</span><br><span class="line">            index  index.html index.htm; #index，会找index.html，找不到然后再找index.htm</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        #error_page  404              /404.html;</span><br><span class="line">        # redirect server error pages to the static page /50x.html</span><br><span class="line">        #</span><br><span class="line">        error_page   500 502 503 504  /50x.html;</span><br><span class="line">        location = /50x.html &#123;</span><br><span class="line">            root   html;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>配置文件结构：</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190905212024.png" alt=""></p>
<ul>
<li><p>一个server代表一个web服务器（或虚拟机）。</p>
</li>
<li><p>location表示web服务器处理的一个指令，一个server一般有多个location来处理多个请求。</p>
</li>
</ul>
<p>还可以添加一个模块就是mail，用来处理邮件相关的协议。默认是没有添加的。</p>
<h3 id="nginx部署静态网页"><a href="#nginx部署静态网页" class="headerlink" title="nginx部署静态网页"></a>nginx部署静态网页</h3><p>在nginx目录下，创建一个demo目录，放入一个newdetail.html文件。</p>
<p>在配置文件的server下添加如下内容：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">location /newdetail.html &#123;</span><br><span class="line">    root demo;</span><br><span class="line">       index newdetail.html;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>现在就可以通过IP加对应的html文件就可以访问了：</p>
<p><a href="http://192.168.80.110/newdetail.html" target="_blank" rel="noopener">http://192.168.80.110/newdetail.html</a></p>
<h3 id="IP与域名"><a href="#IP与域名" class="headerlink" title="IP与域名"></a>IP与域名</h3><p>二者关系</p>
<ul>
<li>一个IP可以被多个域名绑定</li>
<li>一个域名只能绑定一个IP</li>
</ul>
<p>浏览器首先通过DNS向DNS域名服务器解析域名，得到IP，然后通过IP去访问域名对应的网站。</p>
<p>域名解析服务器：</p>
<ul>
<li>Pod DNS+<ul>
<li>首选：119.29.29.29</li>
<li>备选：182.254.116.116</li>
</ul>
</li>
<li>114DNS<ul>
<li>首选：114.114.114.114</li>
<li>备选：114.114.114.115</li>
</ul>
</li>
<li>阿里AliDNS<ul>
<li>首选：223.5.5.5</li>
<li>备选：223.6.6.6</li>
</ul>
</li>
</ul>
<p>hosts文件：</p>
<p>hosts也是解析域名得到IP，相等于域名服务器。直接通过hosts文件可以解析。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1 php</span><br><span class="line">127.0.0.1 websecurity.com127.0.0.1       activate.navicat.com</span><br></pre></td></tr></table></figure>
<p>反向代理的前提：有多台web服务器。</p>
<h3 id="反向代理设置"><a href="#反向代理设置" class="headerlink" title="反向代理设置"></a>反向代理设置</h3><p>环境</p>
<ul>
<li><p>反向代理服务器-windows</p>
</li>
<li><p>两台web服务器</p>
<ul>
<li>一台master: 182.168.80.110</li>
<li>一台node1: 192.168.80.111</li>
</ul>
</li>
</ul>
<p>hosts文件修改：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1 master.com</span><br><span class="line">127.0.0.1 node.com</span><br></pre></td></tr></table></figure>
<p>配置文件修改：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">设置反向代理</span></span><br><span class="line">upstream master.test &#123;</span><br><span class="line">    server 182.168.80.110:80;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">   upstream node.test &#123;</span><br><span class="line">    server 182.168.80.111:80;</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta">#</span><span class="bash">需要代理的服务器信息</span></span><br><span class="line"><span class="meta">#</span><span class="bash">master 192.168.80.110</span></span><br><span class="line"><span class="meta">#</span><span class="bash">node 192.168.80.111</span></span><br><span class="line"></span><br><span class="line">server&#123;</span><br><span class="line">    #监听的端口</span><br><span class="line">	listen 80;</span><br><span class="line"><span class="meta">	#</span><span class="bash">通过什么域名访问web服务器</span></span><br><span class="line">	server_name master.com;</span><br><span class="line">	location / &#123;</span><br><span class="line">	    #设置代理</span><br><span class="line">		proxy_pass http://master.test</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">server&#123;</span><br><span class="line">    #监听的端口</span><br><span class="line">	listen 80;</span><br><span class="line"><span class="meta">	#</span><span class="bash">通过什么域名访问web服务器</span></span><br><span class="line">	server_name node.com;</span><br><span class="line">	location / &#123;</span><br><span class="line">	    #设置代理</span><br><span class="line">		proxy_pass http://node.test</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="负载均衡设置"><a href="#负载均衡设置" class="headerlink" title="负载均衡设置"></a>负载均衡设置</h3><p>hosts文件配置：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1 testnginx.com</span><br></pre></td></tr></table></figure>
<p>设置配置文件：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">设置反向代理和负载均衡</span></span><br><span class="line">upstream linux.test &#123;</span><br><span class="line">    server 192.168.80.110:80;</span><br><span class="line">	server 192.168.80.111:80;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">需要代理的服务器信息</span></span><br><span class="line"><span class="meta">#</span><span class="bash">master 192.168.80.110</span></span><br><span class="line"><span class="meta">#</span><span class="bash">node 192.168.80.111</span></span><br><span class="line"></span><br><span class="line">server&#123;</span><br><span class="line">    #监听的端口</span><br><span class="line">	listen 80;</span><br><span class="line"><span class="meta">	#</span><span class="bash">通过什么域名访问web服务器</span></span><br><span class="line">	server_name testnginx.com;</span><br><span class="line">	location / &#123;</span><br><span class="line">	    #设置代理</span><br><span class="line">		proxy_pass http://linux.test;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>重启nginx。一定要将之前的nginx关闭，然后重启。注意，去任务管理器查看一下是否还有nginx进程。</p>
<p>负载均衡还可以设置权重，如下：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">设置反向代理和负载均衡</span></span><br><span class="line">upstream linux.test &#123;</span><br><span class="line">    server 192.168.80.110:80 weight=5; #weight设置权重</span><br><span class="line">	server 192.168.80.111:80 weight=1;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>反向代理步骤：</p>
<ul>
<li>通过浏览器访问server模块中的server_name对应的域名</li>
<li>服务器去找location /</li>
<li>需要在里面设置代理：proxy_pass url;<ul>
<li>url可以自己编一个</li>
</ul>
</li>
<li>通过这个url的名字去找upstream模块</li>
<li>找到之后，去访问该模块中server对应的地址</li>
</ul>
<p>负载均衡是在反向代理基础上实现的：</p>
<ul>
<li>入口：server模块里面的server_name对应的域名</li>
<li>进入到location /<ul>
<li>发现是一个代理：里面有proxy_pass + url</li>
</ul>
</li>
<li>通过这个url的名字去找upstream<ul>
<li>所有的web服务器的ip都在一个upstream里面</li>
<li>默认情况下处理请求的机会均等。</li>
<li>也可以设置权重：<ul>
<li>weight=1;</li>
<li>最小值为1</li>
<li>最大值没有上限</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>nginx无法处理动态数据，比如登陆，注册。这时候nginx需要调用第三方模块去处理。</p>
<p>这个时候可以采用CGI。程序员调用CGI的接口完成数据处理。浏览器调用CGI，就要涉及到HTTP协议。</p>
<h2 id="CGI"><a href="#CGI" class="headerlink" title="CGI"></a>CGI</h2><p>CGI：公共网关接口，Common Gateway Inerface，简称CGI。</p>
<p>在物理层面上是一段程序，运行在服务器上，提供同客户端HTML页面的接口。</p>
<p>CGI程序如何工作的：</p>
<ul>
<li>web服务器，收到一个请求</li>
<li>web服务器fork一个子进程<ul>
<li>每处理一个请求，都会创建一个子进程</li>
</ul>
</li>
<li>数据处理完成之后，该CGI进程会被web服务器杀死</li>
</ul>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190906182544.png" alt=""></p>
<p>CGI的缺点：</p>
<ul>
<li>需要频繁的创建进程</li>
<li>web服务器效率低</li>
</ul>
<p>改进：</p>
<ul>
<li>使用FASTCGI</li>
</ul>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190906183617.png" alt=""></p>
<h2 id="FastCGI"><a href="#FastCGI" class="headerlink" title="FastCGI"></a>FastCGI</h2><p>FastCGI是语言无关的，可伸缩架构的CGI开放扩展。其主要行为是将CGI解释器进程保持在内存中进行管理调度，因此获得较高的性能。</p>
<p>FastCGI的工作原理：</p>
<ul>
<li>Web server启动时载入FastCGI进程管理器</li>
<li>FastCGI进程管理器自身初始化，启动拖个CGI解释器进程并等待来自Web Server的连接</li>
<li>当客户端请求到达Web Server时，FastCGI进程管理器选择并连接到一个CGI解释器</li>
<li>FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回Web Server</li>
</ul>
<p>悲剧的事情：</p>
<ul>
<li>nginx下FastCGI与服务器是分离的</li>
<li>FastCGI可使用spawn-fcgi或者php-fpm来管理</li>
</ul>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190906185737.png" alt=""></p>
<h3 id="FastCGI安装"><a href="#FastCGI安装" class="headerlink" title="FastCGI安装"></a>FastCGI安装</h3><p>FCGI安装：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">下载FCGI</span></span><br><span class="line">git clone https://github.com/sknown/fcgi.git</span><br><span class="line">cd fcgi</span><br><span class="line"><span class="meta">#</span><span class="bash">安装</span></span><br><span class="line">./configure</span><br><span class="line">make install</span><br></pre></td></tr></table></figure>
<p>spawn-fcgi安装：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">下载spawn-fcgi</span></span><br><span class="line">wget http://download.lighttpd.net/spawn-fcgi/releases-1.6.x/spawn-fcgi-1.6.4.tar.gz</span><br><span class="line"><span class="meta">#</span><span class="bash">解压</span></span><br><span class="line">tar zxvf spawn-fcgi-1.6.4.tar.gz</span><br><span class="line">cd spawn-fcgi-1.6.4</span><br><span class="line"><span class="meta">#</span><span class="bash">安装</span></span><br><span class="line">./configure</span><br><span class="line">make install</span><br></pre></td></tr></table></figure>
<h3 id="spawn-fcgi"><a href="#spawn-fcgi" class="headerlink" title="spawn-fcgi"></a>spawn-fcgi</h3><p>spwan-fcgi是一个代理工作，完成nginx和fastcgi之间的进程间通信。</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190906191811.png" alt=""></p>
<ul>
<li>nginx将数据发给指定端口</li>
<li>spawn-fcgi收到数据后，查看是否有fastCGI处理该请求，如果没有就fork一个fastCGI来处理该请求，否则直接将数据发送给存在的fastCGI</li>
<li>fastCGI处理请求，并回应请求</li>
<li>spawn-fcgi收到响应，就转发给nginx</li>
</ul>
<p>fastCGI是spawn-fcgi的子进程。spawn-fcgi就可以重定向fastcgi的标准输出到管道的写段。spawn-fcgi直接读管道，然后发送给nginx。</p>
<h2 id="nginx配置FastCGI"><a href="#nginx配置FastCGI" class="headerlink" title="nginx配置FastCGI"></a>nginx配置FastCGI</h2><p>将nginx无法处理的请求，交给FastCGI，即将数据转发到对应端口。</p>
<p>nginx配置文件修改：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">处理一个指令<span class="built_in">test</span></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> url: http://192.168.80.110/<span class="built_in">test</span></span></span><br><span class="line">location /test &#123;</span><br><span class="line">     #配置FASTCGI模块</span><br><span class="line">     fastcgi_pass 127.0.0.1:9001;#localhost:90001, 192.168.80.110:90001(本地真实IP)</span><br><span class="line">     #一个端口对应一个进程，将要处理的数据发送到9001端口，然后将9001端口绑定到spawn-fcgi</span><br><span class="line">     include fastcgi.conf; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>spawn-fcgi的使用：</p>
<ul>
<li>编写一个fcgi程序，编译出来的程序名为test</li>
<li>启动程序</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">spawn-fcgi -a IP -p Port -f fastcgi-程序</span><br><span class="line"><span class="meta">#</span><span class="bash">IP：服务器IP，这里的IP要跟nginx配置文件中对应</span></span><br><span class="line"><span class="meta">#</span><span class="bash">Port:服务器将数据发送到的端口</span></span><br><span class="line"><span class="meta">#</span><span class="bash">fastcgi-程序:spawn-fcgi启动的可执行fastcgi程序</span></span><br></pre></td></tr></table></figure>
<p>这里我们以源码中给出的example来演示，编译<code>fcgi/examples/echo.c</code>文件得到test文件，echo.c实现的功能是将请求的信息打印出来。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gcc echo.c -lfgci -o test #需要加上fcgi动态库</span><br></pre></td></tr></table></figure>
<p>启动程序出错:</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">[root@k8s-node1 spawn-fcgi-1.6.4]# spawn-fcgi -a 127.0.0.1 -p 9001 -f ./test</span><br><span class="line">spawn-fcgi: child exited with: 127</span><br><span class="line">[root@k8s-node1 spawn-fcgi-1.6.4]# spawn-fcgi -a 127.0.0.1 -p 9001 -f ./test -n</span><br><span class="line">sh: /root/download/spawn-fcgi-1.6.4/test: No such file or directory</span><br><span class="line">[root@k8s-node1 spawn-fcgi-1.6.4]# cd ..</span><br><span class="line">[root@k8s-node1 download]# cd ..</span><br><span class="line">[root@k8s-node1 ~]# spawn-fcgi -a 127.0.0.1 -p 9001 -f ./test -n</span><br><span class="line">./test: error while loading shared libraries: libfcgi.so.0: cannot open shared object file: No such file or directory</span><br><span class="line">[root@k8s-node1 ~]# find / -name  libfcgi.so.0</span><br><span class="line">/root/download/fcgi/libfcgi/.libs/libfcgi.so.0</span><br><span class="line">/usr/lib/libfcgi.so.0</span><br><span class="line">/usr/local/lib/libfcgi.so.0</span><br><span class="line">[root@k8s-node1 ~]# vi /etc/ld.so.conf #在文件末尾添加： /usr/local/lib</span><br><span class="line">[root@k8s-node1 ~]# ldconfig</span><br><span class="line">[root@k8s-node1 ~]# spawn-fcgi -a 127.0.0.1 -p 9001 -f ./test</span><br><span class="line">spawn-fcgi: child spawned successfully: PID: 127212</span><br></pre></td></tr></table></figure>
<p>如果启动程序错误，可以添加<code>-n</code>来查看错误信息。上面出错是由于找不到动态文件。</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190907084755.png" alt=""></p>
<p>上面是直接在地址栏输入地址带参数，这属于get请求，下面我们测试一下post请求。</p>
<p>首先，编写一个简单的html文件：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">hello</span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">method</span>=<span class="string">"post"</span> <span class="attr">action</span>=<span class="string">"http://192.168.80.110/test"</span>&gt;</span></span><br><span class="line"></span><br><span class="line">	<span class="tag">&lt;<span class="name">p</span>&gt;</span><span class="tag">&lt;<span class="name">label</span>&gt;</span>姓名：<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">name</span>=<span class="string">"username"</span> <span class="attr">placeholder</span>=<span class="string">"贵姓"</span> <span class="attr">autofocus</span>=<span class="string">"autofocus"</span>&gt;</span><span class="tag">&lt;/<span class="name">label</span>&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">p</span>&gt;</span><span class="tag">&lt;<span class="name">label</span>&gt;</span>电话：<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"tel"</span> <span class="attr">name</span>=<span class="string">"phone"</span> <span class="attr">placeholder</span>=<span class="string">"号码"</span> <span class="attr">required</span>=<span class="string">"required"</span>&gt;</span><span class="tag">&lt;/<span class="name">label</span>&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"submit"</span> <span class="attr">value</span>=<span class="string">"Submit"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">form</span>&gt;</span></span><br><span class="line">    </span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>在浏览器中打开该文件，在输入框中输入姓名和电话。点击提交。页面跳转到如下界面：</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190907090814.png" alt=""></p>
<h3 id="FastCGI-1"><a href="#FastCGI-1" class="headerlink" title="FastCGI"></a>FastCGI</h3><p>环境变量指针：</p>
<p><code>extern char **__environ</code></p>
<p>FCGI_Accept()</p>
<p>fastcgi.conf中常用环境变量：</p>
<ul>
<li>QUERY_STRING: 请求的资源，get请求行的第二部分</li>
<li>REQUEST_METHOD：请求方法，get/post</li>
</ul>
<h2 id="部署Web实现文件上传操作"><a href="#部署Web实现文件上传操作" class="headerlink" title="部署Web实现文件上传操作"></a>部署Web实现文件上传操作</h2><p>web代码可以去我的csdn博客下载：<a href="https://download.csdn.net/download/qq_25774883/11692288" target="_blank" rel="noopener">https://download.csdn.net/download/qq_25774883/11692288</a></p>
<p>或者见这篇博客：<a href="https://www.codetd.com/article/5307804" target="_blank" rel="noopener">https://www.codetd.com/article/5307804</a></p>
<p>部署流程：</p>
<ul>
<li><p>将zyFile2拷贝到nginx安装目录：<code>usr/local/nginx</code></p>
</li>
<li><p>查看上传文件对应的html，找到数据提交的位置(nginx需要配置的指令<code>/upload/UploadAction</code>)</p>
</li>
<li><p>修改nginx配置文件，添加一个location</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">  #</span><span class="bash">处理文件上传</span></span><br><span class="line">  location /upload/UploadAction &#123;</span><br><span class="line">       fastcgi_pass 127.0.0.1:9002;</span><br><span class="line">       include fastcgi.conf;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>重新加载配置文件<code>nginx -s reload</code></p>
</li>
<li>编写一个fastcgi程序<ul>
<li>将上传文件的内容保存到FASTDFS存储节点<ul>
<li>先将上传文件内存保存到web服务器</li>
<li>调用FASTDFS API将文件上传到FASTDFS存储节点上，并返回文件ID</li>
<li>得到文件ID，将文件名和文件ID存储到mysql数据库中</li>
<li>将上传的文件从web服务器中删除</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="Post提交数据的四种方式"><a href="#Post提交数据的四种方式" class="headerlink" title="Post提交数据的四种方式"></a>Post提交数据的四种方式</h2><p>HTTP概述：</p>
<ul>
<li><p>HTTP请求分为四个部分:状态行、请求头、空行消息、主体。</p>
</li>
<li><p>协议规定POST提交的数据必须放在消息主题(entity-body)中，但协议并没有规定数据必须使用什么编码格式。</p>
</li>
<li><p>开发者完全可以自己决定消息主题的格式。</p>
</li>
<li>数据发送出去，还要服务端解析成功才有意义，服务端通常是根据请求头(headers)中的Content-type字段来获知请求中的消息主题是用何种方式编码，再对主体 进行解析。</li>
</ul>
<p>四种方式：</p>
<ul>
<li><p>application/w-www-form-urlencoded</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Content-Type: application/x-www-form-urlencoded</span><br><span class="line">username=111&amp;phone=2222</span><br></pre></td></tr></table></figure>
</li>
<li><p>application/json</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Content-Type: application/json</span><br><span class="line">&#123;"title": "test", "sub":[1,2,3]&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>text/xml</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Content-Type: text/xml</span><br><span class="line">&lt;!--?xml version="1.0" ?--&gt;</span><br></pre></td></tr></table></figure>
</li>
<li><p>multipart/form-data</p>
</li>
</ul>
<h2 id="文件下载"><a href="#文件下载" class="headerlink" title="文件下载"></a>文件下载</h2><p>用户下载文件的流程：</p>
<ul>
<li>浏览器访问web服务器</li>
<li>web服务器调用cgi程序</li>
<li>cgi程序需要访问tracker</li>
<li>tracker会提供storage的ip和端口</li>
<li>cgi程序，去访问storage，下载数据</li>
<li>web服务器需要再次将数据发给浏览器</li>
</ul>
<p>改进下载流程：</p>
<ul>
<li>通过浏览器访问web服务器</li>
<li>拿到一个地址，直接通过这个地址来访问storage上的图片</li>
</ul>
<p>如何实现改进下载流程：</p>
<ul>
<li>有一个storage服务器<ul>
<li>在上边部署一个nginx服务器</li>
<li>需要在nginx中添加一个fastdfs模块</li>
</ul>
</li>
</ul>
<p><strong>第一步</strong>：安装nginx：再fastdfs的storage服务器上安装</p>
<p><strong>第二步：</strong>安装<code>fastdfs-nginx-module</code>：</p>
<p>模块下载地址： <a href="http://pan.baidu.com/s/1hs3qp84" target="_blank" rel="noopener">http://pan.baidu.com/s/1hs3qp84</a></p>
<p>下载后上传到linux主机上。</p>
<p>fastdfs-nginx-module_v1.16源码包目录结构：</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190907215754.png" alt=""></p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">tar xzvf fastdfs-nginx-module_v1.16.tar.gz</span><br><span class="line">./configure --add-module=/root/download/fastdfs-nginx-module/src #后面的路径是解压后得到的文件路径</span><br><span class="line"><span class="meta">#</span><span class="bash">make，如果发现报错，显示找不到某个头文件，就通过find查找该头文件，将该目录添加到Makefile中的头文件部分</span></span><br><span class="line"><span class="meta">#</span><span class="bash">注意，应该是objs目录下的Makefile</span></span><br><span class="line">[root@k8s-master ~]# find / -name fdfs_define.h</span><br><span class="line">/root/download/FastDFS/common/fdfs_define.h</span><br><span class="line">/usr/include/fastdfs/fdfs_define.h</span><br><span class="line">[root@k8s-master ~]# find /usr/include -name common_define.h</span><br><span class="line">/usr/include/fastcommon/common_define.h</span><br><span class="line">[root@k8s-master nginx-1.10.1]# ls</span><br><span class="line">auto  CHANGES  CHANGES.ru  conf  configure  contrib  html  LICENSE  Makefile  man  objs  README  src</span><br><span class="line">[root@k8s-master nginx-1.10.1]# cd objs</span><br><span class="line">[root@k8s-master objs]# vim Makefile </span><br><span class="line"><span class="meta">#</span><span class="bash">添加最后面两行</span></span><br><span class="line">ALL_INCS = -I src/core \</span><br><span class="line">        -I src/event \</span><br><span class="line">        -I src/event/modules \</span><br><span class="line">        -I src/os/unix \</span><br><span class="line">        -I /usr/local/include/fastdfs \</span><br><span class="line">        -I /usr/local/include/fastcommon/ \</span><br><span class="line">        -I objs \</span><br><span class="line">        -I src/http \</span><br><span class="line">        -I src/http/modules \</span><br><span class="line">        -I /usr/include/fastdfs \</span><br><span class="line">        -I /usr/include/fastcommon</span><br><span class="line">[root@k8s-master nginx-1.10.1]# make install</span><br></pre></td></tr></table></figure>
<p>重新启动nginx:</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">nginx -s stop</span><br><span class="line">nginx</span><br><span class="line"><span class="meta">#</span><span class="bash">查询nginx进程启动情况</span></span><br><span class="line">[root@k8s-master sbin]# ps aux | grep nginx</span><br><span class="line">root     117083  0.0  0.0  27816   680 ?        Ss   08:53   0:00 nginx: master process nginx</span><br><span class="line">root     117088  0.0  0.0 110276   912 pts/4    R+   08:53   0:00 grep --color=auto nginx</span><br></pre></td></tr></table></figure>
<p>发现只有master进程启动了，worker进程没有启动。这个时候我们进入nginx/logs目录下，查看error.log日志。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[root@k8s-master logs]# ls</span><br><span class="line">access.log  error.log  nginx.pid</span><br><span class="line">[root@k8s-master logs]# cat error.log </span><br><span class="line"><span class="meta">#</span><span class="bash">省略部分日志，直接查看末尾的错误信息</span></span><br><span class="line">ngx_http_fastdfs_process_init pid=117084</span><br><span class="line">[2019-09-07 08:53:14] ERROR - file: shared_func.c, line: 1067, file /etc/fdfs/mod_fastdfs.conf not exist</span><br><span class="line">[2019-09-07 08:53:14] ERROR - file: /root/download/fastdfs-nginx-module/src/common.c, line: 155, load conf file "/etc/fdfs/mod_fastdfs.conf" fail, ret code: 2</span><br><span class="line">2019/09/07 08:53:14 [alert] 117083#0: worker process 117084 exited with fatal code 2 and cannot be respawned</span><br></pre></td></tr></table></figure>
<p>发现是因为再/etc/fdfs目录下找不到mod_fastdfs.conf配置文件。然后我们通过查找该文件并拷贝到该目录下：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cp /root/download/fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs/ #第一个路径为我们下载fastdfs-nginx-module包中一个src路径下的一个配置文件</span><br></pre></td></tr></table></figure>
<p>然后，对配置文件进行修改（<strong>参照存储节点的配置文件修改，也在/etc/fdfs目录下</strong>）：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> the base path to store <span class="built_in">log</span> files</span></span><br><span class="line">base_path=/root/fdfs/storage #storage日志的位置</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> FastDFS tracker_server can ocur more than once, and tracker_server format is</span></span><br><span class="line"><span class="meta">#</span><span class="bash">  <span class="string">"host:port"</span>, host can be hostname or ip address</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> valid only when load_fdfs_parameters_from_tracker is <span class="literal">true</span></span></span><br><span class="line">tracker_server=192.168.80.110:22122  #追踪器地址</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> the port of the <span class="built_in">local</span> storage server</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> the default value is 23000</span></span><br><span class="line">storage_server_port=23000 #跟存储节点端口对应</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> the group name of the <span class="built_in">local</span> storage server</span></span><br><span class="line">group_name=group1  #当前存储节点所属的组</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> <span class="keyword">if</span> the url / uri including the group name</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> <span class="built_in">set</span> to <span class="literal">false</span> when uri like /M00/00/00/xxx</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> <span class="built_in">set</span> to <span class="literal">true</span> when uri like <span class="variable">$&#123;group_name&#125;</span>/M00/00/00/xxx, such as group1/M00/xxx</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> default value is <span class="literal">false</span></span></span><br><span class="line">url_have_group_name = true  #默认为false，不显示组名</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> path(disk or mount point) count, default value is 1</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> must same as storage.conf</span></span><br><span class="line">store_path_count=1  #跟storage对应</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> store_path<span class="comment">#, based 0, if store_path0 not exists, it's value is base_path</span></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> the paths must be exist</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> must same as storage.conf</span></span><br><span class="line">store_path0=/root/fdfs/storage   #跟storage对应，如果有多个，需要全部卸载配置文件中 store_path1...</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> <span class="built_in">set</span> the group count</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> <span class="built_in">set</span> to none zero to support multi-group</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> <span class="built_in">set</span> to 0  <span class="keyword">for</span> single group only</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> groups settings section as [group1], [group2], ..., [groupN]</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> default value is 0</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> since v1.14</span></span><br><span class="line">group_count = 1 #整个FastDFS文件系统一共有多少个组</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash">除去注释</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> group settings <span class="keyword">for</span> group <span class="comment">#1</span></span></span><br><span class="line"><span class="meta">#</span><span class="bash"> since v1.14</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> when support multi-group, uncomment following section</span></span><br><span class="line">[group1]</span><br><span class="line">group_name=group1</span><br><span class="line">storage_server_port=23000</span><br><span class="line">store_path_count=1</span><br><span class="line">store_path0=/root/fdfs/storage</span><br><span class="line"><span class="meta">#</span><span class="bash">store_path1=/home/yuqing/fastdfs1</span></span><br></pre></td></tr></table></figure>
<p>重新启动nginx，发现还是报错了，查看error.log日志：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">ngx_http_fastdfs_process_init pid=118847</span><br><span class="line">[2019-09-07 09:21:47] ERROR - file: ini_file_reader.c, line: 1029, include file "http.conf" not exists, line: "#include http.conf"</span><br><span class="line">[2019-09-07 09:21:47] ERROR - file: /root/download/fastdfs-nginx-module/src/common.c, line: 155, load conf file "/etc/fdfs/mod_fastdfs.conf" fail, ret code: 2</span><br><span class="line">2019/09/07 09:21:47 [alert] 118846#0: worker process 118847 exited with fatal code 2 and cannot be respawned</span><br></pre></td></tr></table></figure>
<p>报错信息是：http.conf文件不存在。</p>
<p>解决措施:</p>
<ul>
<li>从FastDFS的源码安装包中的conf中，将http.conf拷贝到/etc/fdfs</li>
<li>从nginx的源码安装包中的conf中，将mime.types拷贝到/etc/fdfs</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">root@k8s-master FastDFS]# ls</span><br><span class="line">client  conf             fastdfs.spec  init.d   make.sh     README.md   stop.sh  test</span><br><span class="line">common  COPYING-3_0.txt  HISTORY       INSTALL  php_client  restart.sh  storage  tracker</span><br><span class="line">[root@k8s-master FastDFS]# cd conf</span><br><span class="line">[root@k8s-master conf]# ls</span><br><span class="line">anti-steal.jpg  client.conf  http.conf  mime.types  storage.conf  storage_ids.conf  tracker.conf</span><br><span class="line">[root@k8s-master conf]# cp http.conf /etc/fdfs</span><br><span class="line">[root@k8s-master conf]# cd ..</span><br><span class="line">[root@k8s-master FastDFS]# cd ..</span><br><span class="line">[root@k8s-master download]# cd nginx-1.10.1</span><br><span class="line">[root@k8s-master nginx-1.10.1]# ls</span><br><span class="line">auto  CHANGES  CHANGES.ru  conf  configure  contrib  html  LICENSE  Makefile  man  objs  README  src</span><br><span class="line">[root@k8s-master nginx-1.10.1]# cd conf</span><br><span class="line">[root@k8s-master conf]# ls</span><br><span class="line">fastcgi.conf  fastcgi_params  koi-utf  koi-win  mime.types  nginx.conf  scgi_params  uwsgi_params  win-utf</span><br><span class="line">[root@k8s-master conf]# cp mime.types /etc/fdfs</span><br></pre></td></tr></table></figure>
<p>重新启动nginx:</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">[root@k8s-master nginx]# nginx -s stop</span><br><span class="line">[root@k8s-master nginx]# nginx </span><br><span class="line">[root@k8s-master nginx]# ps aux | grep nginx</span><br><span class="line">root     119220  0.0  0.0  27816   684 ?        Ss   09:27   0:00 nginx: master process nginx</span><br><span class="line">nobody   119221  0.0  0.1  28348  1892 ?        S    09:27   0:00 nginx: worker process</span><br><span class="line">root     119257  0.0  0.0 110276   908 pts/4    S+   09:28   0:00 grep --color=auto nginx</span><br></pre></td></tr></table></figure>
<p>发现两个进程都启动成功了。</p>
<p>配置nginx配置文件：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">location /group1/M00 &#123;</span><br><span class="line">    root /root/fdfs/storage/data; #fastDFS的storage存储数据的真实目录</span><br><span class="line">    ngx_fastdfs_module;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>重新启动nginx:</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nginx -s reload</span><br></pre></td></tr></table></figure>
<p>注意如果还是存在无法访问，即404 NOT Found。可能是存储的路径没有访问的权限。因为我把storage存储数据的位置放在root目录下，所以默认是无法访问的，所以需要修改root的权限。·</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[root@k8s-master ~]# cd /</span><br><span class="line">[root@k8s-master /]# chmod 777 root</span><br></pre></td></tr></table></figure>
<h2 id="上传文件服务端CGI程序"><a href="#上传文件服务端CGI程序" class="headerlink" title="上传文件服务端CGI程序"></a>上传文件服务端CGI程序</h2><h1 id="QT"><a href="#QT" class="headerlink" title="QT"></a>QT</h1><h2 id="QT界面搭建"><a href="#QT界面搭建" class="headerlink" title="QT界面搭建"></a>QT界面搭建</h2><p>QT窗口的布局：</p>
<ul>
<li>水平布局：QHBoxLayout</li>
<li>垂直布局：QVBoxLayout</li>
<li>网格布局：QGridLayout</li>
</ul>
<p>绘制窗口背景图:</p>
<ul>
<li>重写这个类的绘图事件<code>paintEvent</code></li>
<li>在这个函数中使用画家类完成绘图操作<ul>
<li>指定绘图设备，就是当前的对象：<code>QPainter p(this);</code></li>
</ul>
</li>
</ul>
<p>鼠标事件的使用：</p>
<ul>
<li><code>mouseMoveEvent()</code></li>
<li><code>mousePressEvent()</code></li>
</ul>
<p>自定义窗口：</p>
<ul>
<li>最终是使用这个自定义类来提升一个基类</li>
<li>先看需要提升的类的数据类型(<code>QPushButton</code>)</li>
<li>自定义的类型需要从<code>QPUshButton</code>派生</li>
<li>使用自定的子类，完成父类的提升</li>
</ul>
<p>Qt中样式表的使用：</p>
<ul>
<li>在控件对应的属性窗口中设置<ul>
<li>QWidget属性-styleSheet</li>
</ul>
</li>
<li>setStyleSheet();</li>
</ul>
<h2 id="数据校验"><a href="#数据校验" class="headerlink" title="数据校验"></a>数据校验</h2><p>正则表达式。</p>
<p>对应的类：<code>QRegExp</code></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">QRegExp <span class="title">reg</span><span class="params">(<span class="string">"a*.b"</span>)</span></span>;</span><br><span class="line"><span class="keyword">bool</span> res = reg.exactMatch(<span class="string">"aacb"</span>);</span><br><span class="line">setPattern(<span class="string">"bcdef*b."</span>);</span><br></pre></td></tr></table></figure>
<h2 id="Qt窗口间通信"><a href="#Qt窗口间通信" class="headerlink" title="Qt窗口间通信"></a>Qt窗口间通信</h2><h2 id="QT中使用Json"><a href="#QT中使用Json" class="headerlink" title="QT中使用Json"></a>QT中使用Json</h2><p>Json的全称是JavaScritp Object Notation.意思是JavaScritpt对象表示法，它是一个基于文本，独立于语言的轻量级数据交换。</p>
<p>Qt5中新增了处理JSON的累，均以QJson开头，在QtCore模块中，不需要额外引入其他模块。</p>
<hr>
<table>
<thead>
<tr>
<th style="text-align:center">类名称</th>
<th style="text-align:center">类说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">QJsonDocument</td>
<td style="text-align:center">读写Json文档</td>
</tr>
<tr>
<td style="text-align:center">QJsonObject</td>
<td style="text-align:center">封装JSON对象</td>
</tr>
<tr>
<td style="text-align:center">QJsonArray</td>
<td style="text-align:center">封装JSON数组</td>
</tr>
<tr>
<td style="text-align:center">QJsonValue</td>
<td style="text-align:center">封装JSON值</td>
</tr>
<tr>
<td style="text-align:center">QJsonObject::iterator</td>
<td style="text-align:center">用于遍历QJsonObject的STL风格的非const遍历器</td>
</tr>
<tr>
<td style="text-align:center">QJsonParseError</td>
<td style="text-align:center">报告Json处理过程中出现的错误</td>
</tr>
</tbody>
</table>
<p>在内存中有一个json格式字符串：</p>
<ul>
<li>首先需要一个QJsonDocument类，将json字符串转为QJsonDocument，利用<code>fromJson</code>静态成员函数进行转换。<code>QJsonDocument::fromJson(str);</code></li>
<li>调用object()成员函数转换位json对象；</li>
<li>调用array()成员函数转换位array对象；</li>
<li>利用QJsonDocument类转换为字符串，利用<code>toJson</code>函数转换为QByteArray。</li>
</ul>
<p>示例：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"mainwindow.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"ui_mainwindow.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QJsonDocument&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QJsonObject&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QJsonValue&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QFile&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QJsonArray&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QDebug&gt;</span></span></span><br><span class="line"></span><br><span class="line">MainWindow::MainWindow(QWidget *parent) :</span><br><span class="line">    QMainWindow(parent),</span><br><span class="line">    ui(<span class="keyword">new</span> Ui::MainWindow)</span><br><span class="line">&#123;</span><br><span class="line">    ui-&gt;setupUi(<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//创建json对象</span></span><br><span class="line">    QJsonObject obj;</span><br><span class="line">    QJsonObject sub;</span><br><span class="line">    sub.insert(<span class="string">"IP"</span>, QJsonValue(<span class="string">"192.168.80.110"</span>));</span><br><span class="line">    sub.insert(<span class="string">"Port"</span>, QJsonValue(<span class="string">"9000"</span>));</span><br><span class="line">    obj.insert(<span class="string">"server"</span>,QJsonValue(sub));</span><br><span class="line">    <span class="comment">//内存中的Json数据写入文件中</span></span><br><span class="line">    <span class="function">QJsonDocument <span class="title">doc</span><span class="params">(obj)</span></span>;</span><br><span class="line">    <span class="comment">//将json对象转换为字符串</span></span><br><span class="line">    QByteArray data = doc.toJson();</span><br><span class="line">    <span class="comment">//字符串写入文件</span></span><br><span class="line">    <span class="function">QFile <span class="title">file</span><span class="params">(<span class="string">"temp.json"</span>)</span></span>;</span><br><span class="line">    file.open(QIODevice::WriteOnly);</span><br><span class="line">    file.write(data);</span><br><span class="line">    file.close();</span><br><span class="line"></span><br><span class="line">    <span class="function">QFile <span class="title">file</span><span class="params">(<span class="string">"temp.json"</span>)</span></span>;</span><br><span class="line">    file.open(QIODevice::ReadOnly);</span><br><span class="line">    QByteArray data = file.readAll();</span><br><span class="line">    file.close();</span><br><span class="line">    <span class="comment">//使用josn文件加载json对象</span></span><br><span class="line">    QJsonDocument doc = QJsonDocument::fromJson(data);</span><br><span class="line">    <span class="comment">//判断数组还是对象</span></span><br><span class="line">    <span class="keyword">if</span>(doc.isObject())&#123;</span><br><span class="line">        QJsonObject obj = doc.object();</span><br><span class="line">        QJsonValue value = obj.value(<span class="string">"server"</span>);</span><br><span class="line">        <span class="keyword">if</span> (value.isObject())&#123;</span><br><span class="line">            QJsonObject subObj = value.toObject();</span><br><span class="line">            <span class="comment">//取值</span></span><br><span class="line">            QString ip = subObj.value(<span class="string">"IP"</span>).toString();</span><br><span class="line">            QString port = subObj.value(<span class="string">"Port"</span>).toString();</span><br><span class="line">            qDebug() &lt;&lt; ip &lt;&lt; port;</span><br><span class="line">         &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//Json数组</span></span><br><span class="line">    QJsonArray arr;</span><br><span class="line">    arr.push_back(QJsonValue(QString(<span class="string">"ii"</span>)));</span><br><span class="line">    arr.push_back(QJsonValue(QString(<span class="string">"jj"</span>)));</span><br><span class="line">    QJsonObject obj;</span><br><span class="line">    obj.insert(<span class="string">"IP"</span>, QJsonValue(<span class="string">"192.168.80.110"</span>));</span><br><span class="line">    obj.insert(<span class="string">"arr"</span>, QJsonValue(arr));</span><br><span class="line">    <span class="function">QJsonDocument <span class="title">doc</span><span class="params">(obj)</span></span>;</span><br><span class="line">    <span class="comment">//将json对象转换为字符串</span></span><br><span class="line">    QByteArray data = doc.toJson();</span><br><span class="line">    <span class="comment">//字符串写入文件</span></span><br><span class="line">    <span class="function">QFile <span class="title">file</span><span class="params">(<span class="string">"array.json"</span>)</span></span>;</span><br><span class="line">    file.open(QIODevice::WriteOnly);</span><br><span class="line">    file.write(data);</span><br><span class="line">    file.close();</span><br><span class="line"></span><br><span class="line">    <span class="function">QFile <span class="title">file</span><span class="params">(<span class="string">"array.json"</span>)</span></span>;</span><br><span class="line">    file.open(QIODevice::ReadOnly);</span><br><span class="line">    QByteArray data = file.readAll();</span><br><span class="line">    file.close();</span><br><span class="line">    <span class="comment">//使用josn文件加载json对象</span></span><br><span class="line">    QJsonDocument doc = QJsonDocument::fromJson(data);</span><br><span class="line">    <span class="comment">//判断数组还是对象</span></span><br><span class="line">    <span class="keyword">if</span>(doc.isObject())&#123;</span><br><span class="line">        QJsonObject obj = doc.object();</span><br><span class="line">        QJsonValue value = obj.value(<span class="string">"arr"</span>);</span><br><span class="line">        <span class="keyword">if</span> (value.isArray())&#123;</span><br><span class="line">            QJsonArray <span class="built_in">array</span> = value.toArray();</span><br><span class="line">            QString str1 = <span class="built_in">array</span>[<span class="number">0</span>].toString();</span><br><span class="line">            QString str2 = <span class="built_in">array</span>[<span class="number">1</span>].toString();</span><br><span class="line">            qDebug() &lt;&lt; str1 &lt;&lt; str2;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">MainWindow::~MainWindow()</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">delete</span> ui;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="QT中使用HTTP协议通信"><a href="#QT中使用HTTP协议通信" class="headerlink" title="QT中使用HTTP协议通信"></a>QT中使用HTTP协议通信</h2><p><code>QNetworkAccessManager</code>类允许应用程序发送网络请求和接收网络应答。</p>
<p>Network Access API都是围绕着一个<code>QNetworkAccessManager</code>对象构造的，这个对象包含着发送请求的一些通用配置和设置。它包含着代理和缓存的配置，以及和这些事物相关的一些信号，并且应答信号可以作为我们检测一个网络操作的进度。</p>
<p>一个<code>QNetworkAccessManager</code>对于一整个Qt应用程序来时已经足够了！</p>
<p>一旦一个<code>QNetworkManager</code>对象被创建了，那么应用程序就可以使用它在网络上发送请求。它提供了一组标准的函数，可以承载网络请求和一些可选的数据，并且每一个请求返回一个<code>QNetworkReply</code>对象。该返回的堆叠包含着返回的请求应带的所有数据。</p>
<h3 id="QNetworkAccessManager类"><a href="#QNetworkAccessManager类" class="headerlink" title="QNetworkAccessManager类"></a><code>QNetworkAccessManager</code>类</h3><p><code>QNetworkAccessManager</code>将会把它收到的请求排队，并行执行的请求数量是依赖于协议的。</p>
<p>目前，对于桌面拍拖的HTTP协议，对于一个主机/端口的组合，可6个请求并行执行。</p>
<p>发送请求：</p>
<ul>
<li>get</li>
<li>post</li>
</ul>
<h3 id="QNetworkRequest类"><a href="#QNetworkRequest类" class="headerlink" title="QNetworkRequest类"></a><code>QNetworkRequest</code>类</h3><p>Network Access API的一部分，并且这个类包含着在网络上发送请求的必要信息。</p>
<ul>
<li>它包含了一个URL和一些可以用来修改请求的附加信息。</li>
<li>将需要发送的HTTP请求协议初始化到该类中<ul>
<li>请求头</li>
<li>数据</li>
<li>URL</li>
</ul>
</li>
</ul>
<h3 id="QNetworkReply类"><a href="#QNetworkReply类" class="headerlink" title="QNetworkReply类"></a><code>QNetworkReply</code>类</h3><p><code>QNetworkAccessManager</code>返回的一个对象，请求完成之后，需要删除该对象。</p>
<p>通过该对象，读取服务器返回的数据。</p>
<p>捕捉信号：</p>
<ul>
<li>readyRead()</li>
<li>finished();</li>
</ul>
<p>读取数据：readall()</p>
<p>以上所有类都属于network模块，需要在pro文件中添加network模块。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">QT       += core gui network</span><br></pre></td></tr></table></figure>
<p>示例：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"mainwindow.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"ui_mainwindow.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QDebug&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QNetworkAccessManager&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QNetworkReply&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QNetworkRequest&gt;</span></span></span><br><span class="line"></span><br><span class="line">MainWindow::MainWindow(QWidget *parent) :</span><br><span class="line">    QMainWindow(parent),</span><br><span class="line">    ui(<span class="keyword">new</span> Ui::MainWindow)</span><br><span class="line">&#123;</span><br><span class="line">    ui-&gt;setupUi(<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//HTTP通信</span></span><br><span class="line">    <span class="comment">//需要一个manager对象，执行get或post请求</span></span><br><span class="line">    <span class="comment">//整个项目中一个QNetworkAccessManager对象就可以了</span></span><br><span class="line">    QNetworkAccessManager * manager = <span class="keyword">new</span> QNetworkAccessManager(<span class="keyword">this</span>); <span class="comment">//this表示，当前窗口结束时，释放创建的对象</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//准备工作 --初始化一个QNetworkRequest对象</span></span><br><span class="line">    QNetworkRequest res;</span><br><span class="line">    <span class="comment">//设置头</span></span><br><span class="line">    QString head = <span class="string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"</span>;</span><br><span class="line">    res.setHeader(QNetworkRequest::UserAgentHeader, head);</span><br><span class="line">    res.setUrl(QUrl(<span class="string">"http://www.baidu.com:80"</span>));</span><br><span class="line">    <span class="comment">//发起Post请求</span></span><br><span class="line">   <span class="comment">// QNetworkReply * reply =  manager-&gt;post(res, ""); //数据为空</span></span><br><span class="line">   <span class="comment">//发起Get请求</span></span><br><span class="line">    QNetworkReply * reply =  manager-&gt;get(res); <span class="comment">//数据为空</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//读取服务器回写的数据</span></span><br><span class="line">    <span class="comment">//QT中ssl库找不到的问题解决:https://www.cnblogs.com/zwj412/p/10352375.html</span></span><br><span class="line">    connect(reply, &amp;QNetworkReply::finished, <span class="keyword">this</span>, [=]&#123;</span><br><span class="line">         <span class="comment">//服务器响应的信息，不包括头部信息</span></span><br><span class="line">        QByteArray data = reply-&gt;readAll();</span><br><span class="line">        QVariant str = reply-&gt;header(QNetworkRequest::LocationHeader); <span class="comment">//获取重定向信息</span></span><br><span class="line">        qDebug() &lt;&lt; str.toString();</span><br><span class="line">        qDebug() &lt;&lt; data;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">MainWindow::~MainWindow()</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">delete</span> ui;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="Mysql数据库表"><a href="#Mysql数据库表" class="headerlink" title="Mysql数据库表"></a>Mysql数据库表</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line">CREATE DATABASE cloud_disk;</span><br><span class="line"></span><br><span class="line">use cloud_disk;</span><br><span class="line"></span><br><span class="line">#user表</span><br><span class="line">CREATE TABLE user(</span><br><span class="line">	id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,</span><br><span class="line">    name VARCHAR (128) NOT NULL,</span><br><span class="line">    nickname VARCHAR(128) NOT NULL,</span><br><span class="line">    password VARCHAR(128) NOT NULL,</span><br><span class="line">    phone VARCHAR(15) NOT NULL,</span><br><span class="line">    createtime VARCHAR(128),</span><br><span class="line">    email VARCHAR(100),</span><br><span class="line">    CONSTRAINT uq_nickname UNIQUE (nickname), #nickname必须唯一</span><br><span class="line">    CONSTRAINT uq_name UNIQUE(name) #name必须唯一</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">INSERT INTO user(name, nickname, password, phone, createtime, email)</span><br><span class="line">VALUES(&apos;mike&apos;, &apos;sh&apos;, &apos;123456&apos;, &apos;10086&apos;, &apos;2017-01-11 17:45:40&apos;, &apos;110909@qq.com&apos;);</span><br><span class="line"></span><br><span class="line">SELECT id FROM user WHERE name = &apos;mike&apos;;</span><br><span class="line"></span><br><span class="line">#file_info表</span><br><span class="line">CREATE TABLE file_info(</span><br><span class="line">	md5 VARCHAR(200) NOT NULL PRIMARY KEY,</span><br><span class="line">    file_id VARCHAR(256) NOT NULL,</span><br><span class="line">    url VARCHAR(512) NOT NULL, #图片的URL</span><br><span class="line">    size BIGINT, #文件大小</span><br><span class="line">    type VARCHAR(20), #文件类型 png,zip...</span><br><span class="line">    count INT #被多少个用户拥有</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">UPDATE file_info SET count=2 WHERE md5 = &quot;bas3iujlkfjdjsaifjd89758uidjf...&quot;;</span><br><span class="line"></span><br><span class="line">#用户文件列表 user_file_list</span><br><span class="line">CREATE TABLE user_file_list(</span><br><span class="line">	user VARCHAR(128) NOT NULL,</span><br><span class="line">    md5 VARCHAR(200) NOT NULL,</span><br><span class="line">    createtime VARCHAR(128),</span><br><span class="line">    filename VARCHAR(128),</span><br><span class="line">    shared_status INT, #共享状态，0为没有共享，1为共享</span><br><span class="line">    pv INT #文件下载量，默认值为0，下载一次加1</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">#查找某个用户的文件列表</span><br><span class="line">SELECT md5 FROM user_file_list WHERE name = &apos;mike&apos;;</span><br><span class="line"></span><br><span class="line">#查看某个文件的属性</span><br><span class="line">SELECT * FROM file_info WHERE md5 =&quot;ddddddd&quot;;</span><br><span class="line"></span><br><span class="line">#设置某个文件是否共享</span><br><span class="line">UPDATE user_file_list SET shared_status = 1 WHERE md5=&quot;dddddd&quot; AND user = &apos;mike&apos;;</span><br><span class="line"></span><br><span class="line">#用户文件数量表 user_file_count</span><br><span class="line">CREATE TABLE user_file_count(</span><br><span class="line">	user VARCHAR(128) NOT NULL PRIMARY KEY,</span><br><span class="line">    count INT</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">#文件共享列表 share_file_list</span><br><span class="line">CREATE TABLE share_file_list(</span><br><span class="line">	user VARCHAR(128) NOT NULL,</span><br><span class="line">    md5 VARCHAR(200) NOT NULL,</span><br><span class="line">    createtime VARCHAR(128),</span><br><span class="line">    filename VARCHAR(128),</span><br><span class="line">    pv INT#文件下载量，默认值为1，下载一次加1</span><br><span class="line">);</span><br></pre></td></tr></table></figure>
<h2 id="MD5"><a href="#MD5" class="headerlink" title="MD5"></a>MD5</h2><p>Message Digest Algorith5 (信息摘要算法5)</p>
<p>MD5算法具有的特点：</p>
<ul>
<li><p>压缩性：</p>
<ul>
<li>任意长度的数据，算出的MD5值长度都是固定的</li>
<li>把一个任意长度的字符串变换成一个定长的十六进制数字串</li>
</ul>
</li>
<li><p>容易计算</p>
<p>从原数据计算MD5值很容易</p>
</li>
<li><p>抗修改性</p>
<p>对原数据进行任何改动，所得到的MD5值都有很大的区别。</p>
</li>
<li><p>强抗碰撞性</p>
<p>已知原数据和其MD5值，想找到一个具有相同MD5值的数据是非常困难的。</p>
</li>
<li><p>MD5过程是不可逆的</p>
</li>
</ul>
<p>MD5的应用：</p>
<ul>
<li>文件校验：文件下载站、论坛数据块、文件系统安全等方案</li>
<li>数字证书<ul>
<li>互联网通讯中标志通信各方身份信息的一串数字</li>
<li>提供了一种在Internet上验证通信实体身份的方式</li>
</ul>
</li>
<li>登陆验证：操作系统的登陆认值，如Unix，各类DSB系统登陆密码</li>
</ul>
<p>MD5算法描述：</p>
<ul>
<li>MD5就是将输入的信息以512位分组，且每一分组被划分位16个32位子分组</li>
<li>经过了一系列的处理后，算法的输出由四个32位分组组成，将这4个32位分组级联后得到一个128位散列值。</li>
</ul>
<h2 id="QT中使用MD5"><a href="#QT中使用MD5" class="headerlink" title="QT中使用MD5"></a>QT中使用MD5</h2><p><code>QCryptographicHash</code></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"mainwindow.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"ui_mainwindow.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QDebug&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QCryptographicHash&gt;</span></span></span><br><span class="line"></span><br><span class="line">MainWindow::MainWindow(QWidget *parent) :</span><br><span class="line">    QMainWindow(parent),</span><br><span class="line">    ui(<span class="keyword">new</span> Ui::MainWindow)</span><br><span class="line">&#123;</span><br><span class="line">    ui-&gt;setupUi(<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">if</span> 0</span></span><br><span class="line">    <span class="comment">//MD5</span></span><br><span class="line">    QByteArray data = <span class="string">"hello world"</span>;</span><br><span class="line">    <span class="function">QCryptographicHash <span class="title">hash</span><span class="params">(QCryptographicHash::Md5)</span></span>;</span><br><span class="line">    <span class="comment">//添加数据</span></span><br><span class="line">    hash.addData(data);</span><br><span class="line">    <span class="comment">//计算</span></span><br><span class="line">    QByteArray arr = hash.result();</span><br><span class="line">    qDebug() &lt;&lt; arr;</span><br><span class="line">    arr = arr.toHex();</span><br><span class="line">    qDebug() &lt;&lt; arr;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line">    QByteArray arr = QCryptographicHash::hash(<span class="string">"hello world"</span>, QCryptographicHash::Md5);</span><br><span class="line">    qDebug() &lt;&lt; arr.toHex();</span><br><span class="line"><span class="meta"># <span class="meta-keyword">endif</span></span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">MainWindow::~MainWindow()</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">delete</span> ui;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="Base64"><a href="#Base64" class="headerlink" title="Base64"></a>Base64</h2><p>Base64是一种用64个字符来表示任意二进制数据的方法</p>
<p>[‘A’, ‘B’, …., ‘Z’, ‘a’, ‘b’, …, ‘z’, ‘0’,…,’9’,’+’,’/‘]</p>
<p>为什么要用Base64编码？</p>
<ul>
<li>在网络上交换数据时，比如说从A地传到B地，往往要经过多个路由设备，由于不同的设备对字符串的处理方式有些不同，这样那些不可见字符就可能被处理错误，这是不利于传输的。</li>
<li>把数据先做一个Base64编码，统统变成可见字符，这样出错的可能性就大大降低了</li>
<li>很多场景下的数据传输要求数据只能由简单通用的字符组成，比如HTTP协议要求请求的首行和请求头都必须由ASCII编码。</li>
<li>能对文本进行简单的加密</li>
</ul>
<p>算法描述：</p>
<ul>
<li>把3个8位字节转化位4个6位的字节</li>
<li>把6位的前面补两个0，形成8位一个字节的形式</li>
<li>如果剩下的字符不足3个字节，则用0填充，输出字符使用‘=’，因此编码后输出的文本末尾可能出现1或2个‘=’，表示补了多少个字节，解码的时候，会自动去掉</li>
</ul>
<h2 id="QT中使用Base64"><a href="#QT中使用Base64" class="headerlink" title="QT中使用Base64"></a>QT中使用Base64</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"mainwindow.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"ui_mainwindow.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;QDebug&gt;</span></span></span><br><span class="line"></span><br><span class="line">MainWindow::MainWindow(QWidget *parent) :</span><br><span class="line">    QMainWindow(parent),</span><br><span class="line">    ui(<span class="keyword">new</span> Ui::MainWindow)</span><br><span class="line">&#123;</span><br><span class="line">    ui-&gt;setupUi(<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//Base64编码</span></span><br><span class="line">    QByteArray base = <span class="string">"你好，世界"</span>;</span><br><span class="line">    base = base.toBase64();</span><br><span class="line">    qDebug() &lt;&lt; base;</span><br><span class="line">    <span class="comment">//解码</span></span><br><span class="line">    base = QByteArray::fromBase64(base); <span class="comment">//静态成员函数</span></span><br><span class="line">    qDebug() &lt;&lt; base.data();</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">MainWindow::~MainWindow()</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">delete</span> ui;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h1 id="协议设计"><a href="#协议设计" class="headerlink" title="协议设计"></a>协议设计</h1><p>文件上传</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0.jpg" alt=""></p>
<p>文件列表获取：</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/%E6%96%87%E4%BB%B6%E5%88%97%E8%A1%A8%E8%8E%B7%E5%8F%96.jpg" alt=""></p>
<p>文件下载：</p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD%20(1" alt="">.jpg)</p>
<p>注册代码实现：<code>reg_cgi.c</code></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"fcgi_config.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"fcgi_stdio.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"cJSON.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;mysql/mysql.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;sys/time.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> HAVE_UNISTD_H</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> _WIN32</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;process.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"><span class="keyword">extern</span> <span class="keyword">char</span> **environ;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SQL_MAX_LEN 1024</span></span><br><span class="line"></span><br><span class="line"><span class="function">MYSQL* <span class="title">mysql_conn</span><span class="params">(<span class="keyword">char</span>* g_user_name, <span class="keyword">char</span>* g_password, <span class="keyword">char</span>* g_db_name)</span></span>&#123;</span><br><span class="line">	MYSQL* g_conn;</span><br><span class="line">	g_conn = mysql_init(<span class="literal">NULL</span>);</span><br><span class="line">	<span class="comment">/*设置字符编码,可能会乱码*/</span></span><br><span class="line">	<span class="comment">//mysql_query(g_conn, "set nemas utf-8");</span></span><br><span class="line">	<span class="comment">/* connect the database */</span></span><br><span class="line">	<span class="comment">//暂时直接设置ip和端口，后面放到配置文件中</span></span><br><span class="line">	<span class="keyword">const</span> <span class="keyword">char</span> *g_host_name = <span class="string">"192.168.80.110"</span>;</span><br><span class="line">	<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> g_db_port = <span class="number">3306</span>;</span><br><span class="line">	mysql_real_connect(g_conn, g_host_name, g_user_name, g_password, g_db_name, g_db_port, <span class="literal">NULL</span>, <span class="number">0</span>); <span class="comment">// 如果失败</span></span><br><span class="line">	<span class="keyword">return</span> g_conn;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">process_result_one</span><span class="params">(MYSQL* conn, <span class="keyword">char</span>* sql_cmd, <span class="keyword">char</span>* buf)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	MYSQL_RES * res_set = <span class="literal">NULL</span>; <span class="comment">//结果集结构的指针</span></span><br><span class="line">	 </span><br><span class="line">	<span class="keyword">if</span> (mysql_query(conn, sql_cmd) != <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">//print_error(conn, "mysql_query error!\n");</span></span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	res_set = mysql_store_result(conn); <span class="comment">//生成结果集</span></span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == res_set)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">//print_error(conn, "mysql_store_result error!\n");</span></span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	MYSQL_ROW row;</span><br><span class="line">	ulong line = <span class="number">0</span>;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//mysql_num_rows接受由mysql_share_result返回的结果结果集，并返回结构集中的行数</span></span><br><span class="line">	line = mysql_num_rows(res_set);</span><br><span class="line">	<span class="keyword">if</span> (line == <span class="number">0</span>)&#123;</span><br><span class="line">		ret = <span class="number">1</span>; <span class="comment">//没有记录集</span></span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span>(line &gt; <span class="number">0</span> &amp;&amp; buf == <span class="literal">NULL</span>) <span class="comment">//如果buf为null，无需保存结果集，只做判断有没有此记录</span></span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">2</span>;<span class="comment">//2有记录但是没有保存</span></span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//mysql_fetch_row从结果结构中提取一行，并把它放到一个行结构中，当数据用完或发生错误时返回NULL</span></span><br><span class="line">	<span class="keyword">if</span> ((row = mysql_fetch_row(res_set)) != <span class="literal">NULL</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="keyword">if</span> (row[<span class="number">0</span>] != <span class="literal">NULL</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">strcpy</span>(buf,row[<span class="number">0</span>]);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">END:</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span>(res_set != <span class="literal">NULL</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">//完成所有对数据的操作后，调用mysql_free_result来善后处理</span></span><br><span class="line">		mysql_free_result(res_set);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">return</span> ret;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">char</span> * <span class="title">return_status</span><span class="params">(<span class="keyword">char</span> * status_num)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">char</span> * out = <span class="literal">NULL</span>;</span><br><span class="line">	cJSON * root = cJSON_CreateObject(); <span class="comment">//创建json项目</span></span><br><span class="line">	cJSON_AddStringToObject(root, <span class="string">"code"</span>, status_num); <span class="comment">//&#123;"code","003"&#125;</span></span><br><span class="line">	out = cJSON_Print(root);  <span class="comment">//cJSON to char *</span></span><br><span class="line">	</span><br><span class="line">	cJSON_Delete(root);</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">return</span> out;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">get_reg_info</span><span class="params">(<span class="keyword">char</span>* reg_buf, <span class="keyword">char</span>* user, <span class="keyword">char</span>* nick_name, <span class="keyword">char</span>* pwd, <span class="keyword">char</span>* tel, <span class="keyword">char</span>* email)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	<span class="comment">/*</span></span><br><span class="line"><span class="comment">	&#123;</span></span><br><span class="line"><span class="comment">		userName: xxx</span></span><br><span class="line"><span class="comment">		nickName: xxx	</span></span><br><span class="line"><span class="comment">		firstPwd: xxx</span></span><br><span class="line"><span class="comment">		phone: xxx</span></span><br><span class="line"><span class="comment">		email: xxx</span></span><br><span class="line"><span class="comment">	&#125;	</span></span><br><span class="line"><span class="comment">	*/</span></span><br><span class="line">	<span class="comment">//解析json包</span></span><br><span class="line">	<span class="comment">//解析一个json字符串为cJson对象</span></span><br><span class="line">	cJSON  * root = cJSON_Parse(reg_buf);</span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == root)</span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//返回指定字符串对象的json对象</span></span><br><span class="line">	<span class="comment">//用户</span></span><br><span class="line">	cJSON * child1 = cJSON_GetObjectItem(root, <span class="string">"userName"</span>);</span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == child1)&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="built_in">strcpy</span>(user, child1-&gt;valuestring); <span class="comment">//拷贝内容</span></span><br><span class="line"></span><br><span class="line">	cJSON * child2 = cJSON_GetObjectItem(root, <span class="string">"nickName"</span>);</span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == child2)</span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">strcpy</span>(nick_name, child2-&gt;valuestring);</span><br><span class="line"></span><br><span class="line">	cJSON * child3 = cJSON_GetObjectItem(root, <span class="string">"firstPwd"</span>);</span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == child3)</span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">strcpy</span>(pwd, child3-&gt;valuestring);</span><br><span class="line"></span><br><span class="line">	cJSON * child4 = cJSON_GetObjectItem(root, <span class="string">"phone"</span>);</span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == child4)</span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">strcpy</span>(tel, child4-&gt;valuestring);</span><br><span class="line"></span><br><span class="line">	cJSON * child5 = cJSON_GetObjectItem(root, <span class="string">"email"</span>);</span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == child5)</span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">strcpy</span>(email, child5-&gt;valuestring);</span><br><span class="line"></span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (root != <span class="literal">NULL</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		cJSON_Delete(root); <span class="comment">//删除json对象</span></span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">分为三步：</span></span><br><span class="line"><span class="comment">将客户端发送过来的数据进行解析，获取用户名、密码等信息</span></span><br><span class="line"><span class="comment">判断表user中是否存在该记录</span></span><br><span class="line"><span class="comment">如果不存在，将数据插入数据库</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">user_register</span><span class="params">(<span class="keyword">char</span> * reg_buf)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	MYSQL * conn = <span class="literal">NULL</span>;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//获取数据库用户名，用户密码，数据库标示等信息</span></span><br><span class="line">	<span class="keyword">char</span> mysql_user[<span class="number">256</span>] = <span class="string">"root"</span>;</span><br><span class="line">	<span class="keyword">char</span> mysql_pwd[<span class="number">256</span>] = <span class="string">"zxcvfdsa321"</span>;</span><br><span class="line">	<span class="keyword">char</span> mysql_db[<span class="number">256</span>] = <span class="string">"cloud_disk"</span>;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//ret = get_mysql_info(mysql_user, mysql_pwd, mysql_db);</span></span><br><span class="line">	<span class="keyword">if</span> (ret != <span class="number">0</span>)&#123;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//获取用户信息</span></span><br><span class="line">	<span class="keyword">char</span> user[<span class="number">128</span>];</span><br><span class="line">	<span class="keyword">char</span> nick_name[<span class="number">128</span>];</span><br><span class="line">	<span class="keyword">char</span> pwd[<span class="number">128</span>];</span><br><span class="line">	<span class="keyword">char</span> tel[<span class="number">128</span>];</span><br><span class="line">	<span class="keyword">char</span> email[<span class="number">128</span>];</span><br><span class="line"></span><br><span class="line">	ret = get_reg_info(reg_buf, user, nick_name, pwd, tel, email);</span><br><span class="line"></span><br><span class="line">	<span class="comment">//printf("%s,%s,%s,%s,%s",user, nick_name, pwd, tel, email);</span></span><br><span class="line"></span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (<span class="number">0</span> != ret)</span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//连接数据库</span></span><br><span class="line">	conn = mysql_conn(mysql_user, mysql_pwd, mysql_db);</span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == conn)</span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//设置数据库密码，注意处理中文编码问题</span></span><br><span class="line">	mysql_query(conn, <span class="string">"set names utf8"</span>);</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">char</span> sql_cmd[SQL_MAX_LEN] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">	</span><br><span class="line">	<span class="built_in">sprintf</span>(sql_cmd, <span class="string">"select * from user where name = '%s'"</span>, user);</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//查看用户是否存在</span></span><br><span class="line">	<span class="keyword">int</span> ret2 = <span class="number">0</span>;</span><br><span class="line">	<span class="comment">//返回值： 0成功并保存记录，1没有记录，2有记录但是没有保存， -1失败</span></span><br><span class="line">	ret2 = process_result_one(conn, sql_cmd, <span class="literal">NULL</span>);</span><br><span class="line">	<span class="keyword">if</span> (ret2 == <span class="number">2</span>) <span class="comment">//如果存在</span></span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-2</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="comment">//当前时间戳</span></span><br><span class="line">	<span class="keyword">time_t</span> tv;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">tm</span>* <span class="title">ptm</span>;</span></span><br><span class="line">	<span class="keyword">char</span> time_str[<span class="number">128</span>] = <span class="string">"2019/9/25 21:27:12"</span>;</span><br><span class="line">	<span class="comment">/*</span></span><br><span class="line"><span class="comment">	//使用行数gettimeofday()函数来得到时间，它的精度可以达到微妙</span></span><br><span class="line"><span class="comment">	time(&amp;tv);</span></span><br><span class="line"><span class="comment">	ptm = localtime(&amp;tv); //把1970-1-1零点零分当作时间系统所偏移的秒数时间转换为本地时间</span></span><br><span class="line"><span class="comment">	//strftime()函数根据区域设置格式本地时间/日期，函数的功能将时间格式化，或者说格式化一个时间字符串</span></span><br><span class="line"><span class="comment">	printf("%ld\n", tv);</span></span><br><span class="line"><span class="comment">	strftime(time_str, sizeof(time_str), "%Y/%m/%d %H:%M:%S", ptm);</span></span><br><span class="line"><span class="comment">	*/</span></span><br><span class="line">	<span class="comment">//sql语句，插入注册信息</span></span><br><span class="line">	<span class="built_in">sprintf</span>(sql_cmd, <span class="string">"insert into user (name, nickname, password, phone, createtime, email) \</span></span><br><span class="line"><span class="string">	values('%s', '%s','%s','%s','%s','%s')"</span>, user, nick_name, pwd, tel, time_str, email);</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (mysql_query(conn, sql_cmd) != <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">END:</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (conn != <span class="literal">NULL</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		mysql_close(conn); <span class="comment">//断开数据库连接</span></span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (FCGI_Accept() &gt;= <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">char</span> *contentLength = getenv(<span class="string">"CONTENT_LENGTH"</span>);</span><br><span class="line">        <span class="keyword">int</span> len;</span><br><span class="line"></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">"Content-type: text/html\r\n"</span></span><br><span class="line">	    <span class="string">"\r\n"</span></span><br><span class="line">	    );</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (contentLength != <span class="literal">NULL</span>) &#123;</span><br><span class="line">            len = strtol(contentLength, <span class="literal">NULL</span>, <span class="number">10</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            len = <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (len &lt;= <span class="number">0</span>) &#123;</span><br><span class="line">	    <span class="built_in">printf</span>(<span class="string">"No data from standard input.&lt;p&gt;\n"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">			<span class="keyword">char</span> buf[<span class="number">4</span>*<span class="number">1024</span>];</span><br><span class="line">            <span class="keyword">int</span> i, ch;</span><br><span class="line">			<span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line">			<span class="keyword">char</span> * out;</span><br><span class="line"></span><br><span class="line">	    <span class="comment">//printf("Standard input:&lt;br&gt;\n&lt;pre&gt;\n");</span></span><br><span class="line">            <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; len; i++) &#123;</span><br><span class="line">                <span class="keyword">if</span> ((ch = getchar()) &lt; <span class="number">0</span>) &#123;</span><br><span class="line">                    <span class="built_in">printf</span>(<span class="string">"Error: Not enough bytes received on standard input&lt;p&gt;\n"</span>);</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">			&#125;</span><br><span class="line">                buf[i] = ch;</span><br><span class="line">            &#125;</span><br><span class="line">			<span class="comment">//printf("%s",buf);</span></span><br><span class="line">			<span class="comment">/*</span></span><br><span class="line"><span class="comment">			注册：</span></span><br><span class="line"><span class="comment">				成功：&#123;"code": "002"&#125;</span></span><br><span class="line"><span class="comment">				该用户已存在：&#123;"code": "003"&#125;</span></span><br><span class="line"><span class="comment">				失败：&#123;"code": "004"&#125;</span></span><br><span class="line"><span class="comment">			*/</span></span><br><span class="line">			</span><br><span class="line">			ret = user_register(buf);</span><br><span class="line">			<span class="keyword">if</span> (ret ==<span class="number">0</span>)<span class="comment">//注册成功</span></span><br><span class="line">			&#123;</span><br><span class="line">				<span class="comment">//返回前端注册情况，002代表成功</span></span><br><span class="line">				out = return_status(<span class="string">"002"</span>);</span><br><span class="line">			&#125;</span><br><span class="line">			<span class="keyword">else</span> <span class="keyword">if</span> (ret == <span class="number">-1</span>)</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="comment">//返回当前注册情况，004代表失败</span></span><br><span class="line">				out = return_status(<span class="string">"004"</span>);</span><br><span class="line">			&#125;</span><br><span class="line">			<span class="keyword">else</span> <span class="keyword">if</span> (ret == <span class="number">-2</span>)</span><br><span class="line">			&#123;</span><br><span class="line">				out = return_status(<span class="string">"003"</span>);</span><br><span class="line">			&#125;</span><br><span class="line">			</span><br><span class="line">			<span class="keyword">if</span> (out != <span class="literal">NULL</span>)</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="built_in">printf</span>(out); <span class="comment">//给前端反馈信息</span></span><br><span class="line">				<span class="built_in">free</span>(out);</span><br><span class="line">			&#125;</span><br><span class="line">            <span class="comment">//printf("\n&lt;/pre&gt;&lt;p&gt;\n");</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125; <span class="comment">/* while */</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>fastcgi配置：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc reg_cgi.c  -o reg_cgi -lcJson -lmysqlclient -lfcgi</span><br><span class="line">spawn-fcgi -a 127.0.0.1 -p 10001 -f ./reg_cgi</span><br></pre></td></tr></table></figure>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190926104335.png" alt=""></p>
<p><img src="https://raw.githubusercontent.com/zxpgo/images/master/img/20190926104414.png" alt=""></p>
<p>登陆代码实现：<code>login_cgi.c</code></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"fcgi_config.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"fcgi_stdio.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">"cJSON.h"</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;mysql/mysql.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> HAVE_UNISTD_H</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> _WIN32</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;process.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">else</span></span></span><br><span class="line"><span class="keyword">extern</span> <span class="keyword">char</span> **environ;</span><br><span class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> SQL_MAX_LEN 1024</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function">MYSQL* <span class="title">mysql_conn</span><span class="params">(<span class="keyword">char</span>* g_user_name, <span class="keyword">char</span>* g_password, <span class="keyword">char</span>* g_db_name)</span></span>&#123;</span><br><span class="line">	MYSQL* g_conn;</span><br><span class="line">	g_conn = mysql_init(<span class="literal">NULL</span>);</span><br><span class="line">	<span class="comment">/*设置字符编码,可能会乱码*/</span></span><br><span class="line">	<span class="comment">//mysql_query(g_conn, "set nemas utf-8");</span></span><br><span class="line">	<span class="comment">/* connect the database */</span></span><br><span class="line">	<span class="comment">//暂时直接设置ip和端口，后面放到配置文件中</span></span><br><span class="line">	<span class="keyword">const</span> <span class="keyword">char</span> *g_host_name = <span class="string">"192.168.80.110"</span>;</span><br><span class="line">	<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> g_db_port = <span class="number">3306</span>;</span><br><span class="line">	mysql_real_connect(g_conn, g_host_name, g_user_name, g_password, g_db_name, g_db_port, <span class="literal">NULL</span>, <span class="number">0</span>); <span class="comment">// 如果失败</span></span><br><span class="line">	<span class="keyword">return</span> g_conn;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">char</span> * <span class="title">return_status</span><span class="params">(<span class="keyword">char</span> * status_num)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">char</span> * out = <span class="literal">NULL</span>;</span><br><span class="line">	cJSON * root = cJSON_CreateObject(); <span class="comment">//创建json项目</span></span><br><span class="line">	cJSON_AddStringToObject(root, <span class="string">"code"</span>, status_num); <span class="comment">//&#123;"code","003"&#125;</span></span><br><span class="line">	out = cJSON_Print(root);  <span class="comment">//cJSON to char *</span></span><br><span class="line">	</span><br><span class="line">	cJSON_Delete(root);</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">return</span> out;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">get_login_info</span><span class="params">(<span class="keyword">char</span>* login_buf, <span class="keyword">char</span>* user, <span class="keyword">char</span>* pwd)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	<span class="comment">/*</span></span><br><span class="line"><span class="comment">	&#123;</span></span><br><span class="line"><span class="comment">		user: xxx</span></span><br><span class="line"><span class="comment">		pwd: xxx</span></span><br><span class="line"><span class="comment">	&#125;	</span></span><br><span class="line"><span class="comment">	*/</span></span><br><span class="line">	<span class="comment">//解析json包</span></span><br><span class="line">	<span class="comment">//解析一个json字符串为cJson对象</span></span><br><span class="line">	cJSON  * root = cJSON_Parse(login_buf);</span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == root)</span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line"></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//返回指定字符串对象的json对象</span></span><br><span class="line">	<span class="comment">//用户</span></span><br><span class="line">	cJSON * child1 = cJSON_GetObjectItem(root, <span class="string">"user"</span>);</span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == child1)&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">strcpy</span>(user, child1-&gt;valuestring); <span class="comment">//拷贝内容</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">//密码</span></span><br><span class="line">	cJSON * child2 = cJSON_GetObjectItem(root, <span class="string">"pwd"</span>);</span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == child2)</span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">strcpy</span>(pwd, child2-&gt;valuestring);</span><br><span class="line"></span><br><span class="line">END:</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (root != <span class="literal">NULL</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		cJSON_Delete(root); <span class="comment">//删除json对象</span></span><br><span class="line">		root = <span class="literal">NULL</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">process_result_one</span><span class="params">(MYSQL* conn, <span class="keyword">char</span>* sql_cmd, <span class="keyword">char</span>* pwd)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	</span><br><span class="line">	MYSQL_RES * res_set = <span class="literal">NULL</span>; <span class="comment">//结果集结构的指针</span></span><br><span class="line">	 </span><br><span class="line">	<span class="keyword">if</span> (mysql_query(conn, sql_cmd) != <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">//print_error(conn, "mysql_query error!\n");</span></span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	res_set = mysql_store_result(conn); <span class="comment">//生成结果集</span></span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == res_set)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">//print_error(conn, "mysql_store_result error!\n");</span></span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	MYSQL_ROW row;</span><br><span class="line">	ulong line = <span class="number">0</span>;</span><br><span class="line">	<span class="comment">//mysql_num_rows接受由mysql_share_result返回的结果结果集，并返回结果集中的行数</span></span><br><span class="line">	line = mysql_num_rows(res_set);</span><br><span class="line">	<span class="comment">//printf("line = %d \n", line);</span></span><br><span class="line">	<span class="keyword">if</span> (line == <span class="number">0</span> || pwd == <span class="literal">NULL</span>)&#123;</span><br><span class="line">		ret = <span class="number">-1</span>; <span class="comment">//没有记录集,或者密码为空</span></span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	row = mysql_fetch_row(res_set);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span> (<span class="built_in">strcmp</span>(pwd, row[<span class="number">0</span>]) != <span class="number">0</span>)</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">	<span class="comment">//mysql_fetch_row从结果结构中提取一行，并把它放到一个行结构中，当数据用完或发生错误时返回NULL</span></span><br><span class="line">	<span class="comment">/*</span></span><br><span class="line"><span class="comment">	if ((row = mysql_fetch_row(res_set)) != NULL)</span></span><br><span class="line"><span class="comment">	&#123;</span></span><br><span class="line"><span class="comment">		if (row[0] != NULL)</span></span><br><span class="line"><span class="comment">		&#123;</span></span><br><span class="line"><span class="comment">			strcpy(buf,row[0]);</span></span><br><span class="line"><span class="comment">		&#125;</span></span><br><span class="line"><span class="comment">	&#125;</span></span><br><span class="line"><span class="comment">	printf("%s\n", buf);</span></span><br><span class="line"><span class="comment">	*/</span></span><br><span class="line">END:</span><br><span class="line"></span><br><span class="line">	<span class="keyword">if</span>(res_set != <span class="literal">NULL</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">//完成所有对数据的操作后，调用mysql_free_result来善后处理</span></span><br><span class="line">		mysql_free_result(res_set);</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">return</span> ret;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">分为两步：</span></span><br><span class="line"><span class="comment">将客户端发送过来的数据进行解析，获取用户名、密码</span></span><br><span class="line"><span class="comment">判断表user中是否存在该记录</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">user_login</span><span class="params">(<span class="keyword">char</span> * reg_buf)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">	<span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	MYSQL * conn = <span class="literal">NULL</span>;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//获取数据库用户名，用户密码，数据库标示等信息</span></span><br><span class="line">	<span class="keyword">char</span> mysql_user[<span class="number">256</span>] = <span class="string">"root"</span>;</span><br><span class="line">	<span class="keyword">char</span> mysql_pwd[<span class="number">256</span>] = <span class="string">"zxcvfdsa321"</span>;</span><br><span class="line">	<span class="keyword">char</span> mysql_db[<span class="number">256</span>] = <span class="string">"cloud_disk"</span>;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//ret = get_mysql_info(mysql_user, mysql_pwd, mysql_db);</span></span><br><span class="line">	<span class="comment">//if (ret != 0)&#123;</span></span><br><span class="line">	<span class="comment">//	goto END;</span></span><br><span class="line">	<span class="comment">//&#125;</span></span><br><span class="line">	</span><br><span class="line">	<span class="comment">//获取用户信息</span></span><br><span class="line">	<span class="keyword">char</span> user[<span class="number">128</span>];</span><br><span class="line">	<span class="keyword">char</span> pwd[<span class="number">128</span>];</span><br><span class="line"></span><br><span class="line">	ret = get_login_info(reg_buf, user, pwd);</span><br><span class="line"></span><br><span class="line">	<span class="comment">//printf("ret = %d, %s,%s\n",ret, user, pwd);</span></span><br><span class="line"></span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (<span class="number">0</span> != ret)</span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//连接数据库</span></span><br><span class="line">	conn = mysql_conn(mysql_user, mysql_pwd, mysql_db);</span><br><span class="line">	<span class="keyword">if</span> (<span class="literal">NULL</span> == conn)</span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//设置数据库密码，注意处理中文编码问题</span></span><br><span class="line">	mysql_query(conn, <span class="string">"set names utf8"</span>);</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">char</span> sql_cmd[SQL_MAX_LEN] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">	</span><br><span class="line">	<span class="built_in">sprintf</span>(sql_cmd, <span class="string">"select password from user where name = '%s'"</span>, user);</span><br><span class="line">	</span><br><span class="line">	<span class="comment">//查看用户是否存在</span></span><br><span class="line">	<span class="keyword">int</span> ret2 = <span class="number">0</span>;</span><br><span class="line">	<span class="comment">//返回值：-1失败，0成功</span></span><br><span class="line">	ret2 = process_result_one(conn, sql_cmd, pwd);</span><br><span class="line">	<span class="keyword">if</span> (ret2 != <span class="number">0</span>) <span class="comment">//密码不对或者用户名不对</span></span><br><span class="line">	&#123;</span><br><span class="line">		ret = <span class="number">-1</span>;</span><br><span class="line">		<span class="keyword">goto</span> END;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line"></span><br><span class="line">END:</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (conn != <span class="literal">NULL</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		mysql_close(conn); <span class="comment">//断开数据库连接</span></span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">return</span> ret;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (FCGI_Accept() &gt;= <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">char</span> *contentLength = getenv(<span class="string">"CONTENT_LENGTH"</span>);</span><br><span class="line">        <span class="keyword">int</span> len;</span><br><span class="line"></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">"Content-type: text/html\r\n"</span></span><br><span class="line">	    <span class="string">"\r\n"</span></span><br><span class="line">	    );</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (contentLength != <span class="literal">NULL</span>) &#123;</span><br><span class="line">            len = strtol(contentLength, <span class="literal">NULL</span>, <span class="number">10</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            len = <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (len &lt;= <span class="number">0</span>) &#123;</span><br><span class="line">	    <span class="built_in">printf</span>(<span class="string">"No data from standard input.&lt;p&gt;\n"</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">			<span class="keyword">char</span> buf[<span class="number">4</span>*<span class="number">1024</span>];</span><br><span class="line">            <span class="keyword">int</span> i, ch;</span><br><span class="line">			<span class="keyword">int</span> ret = <span class="number">0</span>;</span><br><span class="line">			<span class="keyword">char</span> * out;</span><br><span class="line"></span><br><span class="line">	    <span class="comment">//printf("Standard input:&lt;br&gt;\n&lt;pre&gt;\n");</span></span><br><span class="line">            <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; len; i++) &#123;</span><br><span class="line">                <span class="keyword">if</span> ((ch = getchar()) &lt; <span class="number">0</span>) &#123;</span><br><span class="line">                    <span class="built_in">printf</span>(<span class="string">"Error: Not enough bytes received on standard input&lt;p&gt;\n"</span>);</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">			&#125;</span><br><span class="line">                buf[i] = ch;</span><br><span class="line">            &#125;</span><br><span class="line">			<span class="comment">//printf("loginINFO: %s\n",buf);</span></span><br><span class="line">			<span class="comment">/*</span></span><br><span class="line"><span class="comment">			登陆：</span></span><br><span class="line"><span class="comment">				成功：&#123;"code": "000"&#125;</span></span><br><span class="line"><span class="comment">				失败：&#123;"code": "001"&#125;</span></span><br><span class="line"><span class="comment">			*/</span></span><br><span class="line">			</span><br><span class="line">			ret = user_login(buf);</span><br><span class="line">			<span class="keyword">if</span> (ret == <span class="number">0</span>)<span class="comment">//登陆成功</span></span><br><span class="line">			&#123;</span><br><span class="line">				<span class="comment">//返回登陆情况，000代表成功</span></span><br><span class="line">				out = return_status(<span class="string">"000"</span>);</span><br><span class="line">			&#125;</span><br><span class="line">			<span class="keyword">else</span> <span class="keyword">if</span> (ret == <span class="number">-1</span>)</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="comment">//返回当前注册情况，001代表失败</span></span><br><span class="line">				out = return_status(<span class="string">"001"</span>);</span><br><span class="line">			&#125;</span><br><span class="line">			</span><br><span class="line">			<span class="keyword">if</span> (out != <span class="literal">NULL</span>)</span><br><span class="line">			&#123;</span><br><span class="line">				<span class="built_in">printf</span>(out); <span class="comment">//给前端反馈信息</span></span><br><span class="line">				<span class="built_in">free</span>(out);</span><br><span class="line">			&#125;</span><br><span class="line">            <span class="comment">//printf("\n&lt;/pre&gt;&lt;p&gt;\n");</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125; <span class="comment">/* while */</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

      
    </div>
    
    
    

    
      <div>
        <div id="wechat_subscriber" style="display: block; padding: 10px 0; margin: 20px auto; width: 100%; text-align: center">
    <img id="wechat_subscriber_qcode" src="/images/wechat-qcode.jpg" alt="zxp wechat" style="width: 200px; max-width: 100%;"/>
    <div>欢迎关注微信公众号！</div>
</div>

      </div>
    

    
      <div>
        <div style="padding: 10px 0; margin: 20px auto; width: 90%; text-align: center;">
  <div></div>
  <button id="rewardButton" disable="enable" onclick="var qr = document.getElementById('QR'); if (qr.style.display === 'none') {qr.style.display='block';} else {qr.style.display='none'}">
    <span>打赏</span>
  </button>
  <div id="QR" style="display: none;">

    
      <div id="wechat" style="display: inline-block">
        <img id="wechat_qr" src="/images/WeChatpay.jpg" alt="zxp 微信支付"/>
        <p>微信支付</p>
      </div>
    

    
      <div id="alipay" style="display: inline-block">
        <img id="alipay_qr" src="/images/Alipay.jpg" alt="zxp 支付宝"/>
        <p>支付宝</p>
      </div>
    

    

  </div>
</div>

      </div>
    

    
      <div>
        <ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者：</strong>
    zxp
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="https://zxpgo.github.io/2019/11/18/云盘项目/" title="图床项目笔记">https://zxpgo.github.io/2019/11/18/云盘项目/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>
    本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/3.0/" rel="external nofollow" target="_blank">CC BY-NC-SA 3.0</a> 许可协议。转载请注明出处！
  </li>
</ul>

      </div>
    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tag/项目/" rel="tag"># 项目</a>
          
        </div>
      

      
      
        <div class="post-widgets">
        

        

        
          
          <div id="needsharebutton-postbottom">
            <span class="btn">
              <i class="fa fa-share-alt" aria-hidden="true"></i>
            </span>
          </div>
        
        </div>
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2019/11/04/操作系统复习/" rel="next" title="操作系统学习笔记">
                <i class="fa fa-chevron-left"></i> 操作系统学习笔记
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2019/11/25/C++工程师校招面试考点汇总--牛客网/" rel="prev" title="C++工程师校招面试考点汇总--牛客网">
                C++工程师校招面试考点汇总--牛客网 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  
    <div class="comments" id="comments">
      <div id="lv-container" data-id="city" data-uid="MTAyMC8zODgxNC8xNTM0Mg=="></div>
    </div>

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image"
                src="/images/avatar.gif"
                alt="zxp" />
            
              <p class="site-author-name" itemprop="name">zxp</p>
              <p class="site-description motion-element" itemprop="description"></p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">176</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/categories/index.html">
                  <span class="site-state-item-count">16</span>
                  <span class="site-state-item-name">分类</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/tags/index.html">
                  <span class="site-state-item-count">48</span>
                  <span class="site-state-item-name">标签</span>
                </a>
              </div>
            

          </nav>

          
            <div class="feed-link motion-element">
              <a href="/atom.xml" rel="alternate">
                <i class="fa fa-rss"></i>
                RSS
              </a>
            </div>
          

          
            <div class="links-of-author motion-element">
                
                  <span class="links-of-author-item">
                    <a href="https://blog.csdn.net/qq_25774883" target="_blank" title="CSDN">
                      
                        <i class="fa fa-fw fa-globe"></i>CSDN</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="https://github.com/zxpgo/zxpgo" target="_blank" title="GitHub">
                      
                        <i class="fa fa-fw fa-globe"></i>GitHub</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="https://www.linkedin.com/feed/" target="_blank" title="LinkedIn">
                      
                        <i class="fa fa-fw fa-globe"></i>LinkedIn</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="1165772354@qq.com" target="_blank" title="E-Mail">
                      
                        <i class="fa fa-fw fa-envelope"></i>E-Mail</a>
                  </span>
                
            </div>
          

          
          

          
          
            <div class="links-of-blogroll motion-element links-of-blogroll-inline">
              <div class="links-of-blogroll-title">
                <i class="fa  fa-fw fa-link"></i>
                友情链接
              </div>
              <ul class="links-of-blogroll-list">
                
                  <li class="links-of-blogroll-item">
                    <a href="http://theme-next.iissnan.com" title="Next主题" target="_blank">Next主题</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="http://blog.rexking6.top" title="青爷博客" target="_blank">青爷博客</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="https://me.csdn.net/download/qq_25774883" title="CSDN下载" target="_blank">CSDN下载</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="https://www.livere.com/" title="来必力" target="_blank">来必力</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="https://tongji.baidu.com/web/welcome/login" title="百度统计" target="_blank">百度统计</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="https://leancloud.cn/" title="LeanCloud" target="_blank">LeanCloud</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="http://ibruce.info/2015/04/04/busuanzi/" title="不蒜子" target="_blank">不蒜子</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="https://leetcode-cn.com/" title="LeetCode" target="_blank">LeetCode</a>
                  </li>
                
              </ul>
            </div>
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#项目架构"><span class="nav-number">1.</span> <span class="nav-text">项目架构</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#Web服务器"><span class="nav-number">1.1.</span> <span class="nav-text">Web服务器</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#FASTDFS"><span class="nav-number">1.2.</span> <span class="nav-text">FASTDFS</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#FASTDFS概述"><span class="nav-number">1.2.1.</span> <span class="nav-text">FASTDFS概述</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#FASTDFS特点"><span class="nav-number">1.2.2.</span> <span class="nav-text">FASTDFS特点</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#FASTDFS框架中三个角色"><span class="nav-number">1.2.3.</span> <span class="nav-text">FASTDFS框架中三个角色</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#FASTDFS安装"><span class="nav-number">1.2.4.</span> <span class="nav-text">FASTDFS安装</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#FASTDFS配置"><span class="nav-number">1.2.5.</span> <span class="nav-text">FASTDFS配置</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#FASTDFS启动"><span class="nav-number">1.2.6.</span> <span class="nav-text">FASTDFS启动</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#文件上传和下载流程"><span class="nav-number">1.2.7.</span> <span class="nav-text">文件上传和下载流程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#找不到动态库-so的问题"><span class="nav-number">1.2.8.</span> <span class="nav-text">找不到动态库.so的问题</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代码实现FastDFS文件上传和下载"><span class="nav-number">1.2.9.</span> <span class="nav-text">代码实现FastDFS文件上传和下载</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#源码分析"><span class="nav-number">1.2.9.1.</span> <span class="nav-text">源码分析</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#进程方式实现"><span class="nav-number">1.2.9.2.</span> <span class="nav-text">进程方式实现</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Redis"><span class="nav-number">1.3.</span> <span class="nav-text">Redis</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#安装"><span class="nav-number">1.3.1.</span> <span class="nav-text">安装</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#数据类型"><span class="nav-number">1.3.2.</span> <span class="nav-text">数据类型</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#string"><span class="nav-number">1.3.2.1.</span> <span class="nav-text">string</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#List类型："><span class="nav-number">1.3.2.2.</span> <span class="nav-text">List类型：</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#set"><span class="nav-number">1.3.2.3.</span> <span class="nav-text">set</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#sorted"><span class="nav-number">1.3.2.4.</span> <span class="nav-text">sorted</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#hash"><span class="nav-number">1.3.2.5.</span> <span class="nav-text">hash</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#对于key的操作"><span class="nav-number">1.3.2.6.</span> <span class="nav-text">对于key的操作</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#配置文件"><span class="nav-number">1.3.3.</span> <span class="nav-text">配置文件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#数据持久化"><span class="nav-number">1.3.4.</span> <span class="nav-text">数据持久化</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#hiredis-API接口使用"><span class="nav-number">1.3.5.</span> <span class="nav-text">hiredis API接口使用</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#安装-1"><span class="nav-number">1.3.5.1.</span> <span class="nav-text">安装</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#连接数据库"><span class="nav-number">1.3.5.2.</span> <span class="nav-text">连接数据库</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#发送请求命令"><span class="nav-number">1.3.5.3.</span> <span class="nav-text">发送请求命令</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#释放资源"><span class="nav-number">1.3.5.4.</span> <span class="nav-text">释放资源</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Mysql"><span class="nav-number">1.4.</span> <span class="nav-text">Mysql</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#设置默认编码"><span class="nav-number">1.4.1.</span> <span class="nav-text">设置默认编码</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#设置字段名大小写不敏感"><span class="nav-number">1.4.2.</span> <span class="nav-text">设置字段名大小写不敏感</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Shell脚本"><span class="nav-number">1.5.</span> <span class="nav-text">Shell脚本</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#特殊变量"><span class="nav-number">1.5.1.</span> <span class="nav-text">特殊变量</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#变量"><span class="nav-number">1.5.2.</span> <span class="nav-text">变量</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Nginx"><span class="nav-number">1.6.</span> <span class="nav-text">Nginx</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#nginx介绍"><span class="nav-number">1.6.1.</span> <span class="nav-text">nginx介绍</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#正向代理和反向代理"><span class="nav-number">1.6.2.</span> <span class="nav-text">正向代理和反向代理</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#正向代理："><span class="nav-number">1.6.2.1.</span> <span class="nav-text">正向代理：</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#反向代理"><span class="nav-number">1.6.2.2.</span> <span class="nav-text">反向代理</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#安装-2"><span class="nav-number">1.6.3.</span> <span class="nav-text">安装</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#nginx相关操作命令"><span class="nav-number">1.6.4.</span> <span class="nav-text">nginx相关操作命令</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#配置文件-1"><span class="nav-number">1.6.5.</span> <span class="nav-text">配置文件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#nginx部署静态网页"><span class="nav-number">1.6.6.</span> <span class="nav-text">nginx部署静态网页</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#IP与域名"><span class="nav-number">1.6.7.</span> <span class="nav-text">IP与域名</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#反向代理设置"><span class="nav-number">1.6.8.</span> <span class="nav-text">反向代理设置</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#负载均衡设置"><span class="nav-number">1.6.9.</span> <span class="nav-text">负载均衡设置</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#CGI"><span class="nav-number">1.7.</span> <span class="nav-text">CGI</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#FastCGI"><span class="nav-number">1.8.</span> <span class="nav-text">FastCGI</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#FastCGI安装"><span class="nav-number">1.8.1.</span> <span class="nav-text">FastCGI安装</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#spawn-fcgi"><span class="nav-number">1.8.2.</span> <span class="nav-text">spawn-fcgi</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#nginx配置FastCGI"><span class="nav-number">1.9.</span> <span class="nav-text">nginx配置FastCGI</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#FastCGI-1"><span class="nav-number">1.9.1.</span> <span class="nav-text">FastCGI</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#部署Web实现文件上传操作"><span class="nav-number">1.10.</span> <span class="nav-text">部署Web实现文件上传操作</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Post提交数据的四种方式"><span class="nav-number">1.11.</span> <span class="nav-text">Post提交数据的四种方式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#文件下载"><span class="nav-number">1.12.</span> <span class="nav-text">文件下载</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#上传文件服务端CGI程序"><span class="nav-number">1.13.</span> <span class="nav-text">上传文件服务端CGI程序</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#QT"><span class="nav-number">2.</span> <span class="nav-text">QT</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#QT界面搭建"><span class="nav-number">2.1.</span> <span class="nav-text">QT界面搭建</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#数据校验"><span class="nav-number">2.2.</span> <span class="nav-text">数据校验</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Qt窗口间通信"><span class="nav-number">2.3.</span> <span class="nav-text">Qt窗口间通信</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#QT中使用Json"><span class="nav-number">2.4.</span> <span class="nav-text">QT中使用Json</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#QT中使用HTTP协议通信"><span class="nav-number">2.5.</span> <span class="nav-text">QT中使用HTTP协议通信</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#QNetworkAccessManager类"><span class="nav-number">2.5.1.</span> <span class="nav-text">QNetworkAccessManager类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#QNetworkRequest类"><span class="nav-number">2.5.2.</span> <span class="nav-text">QNetworkRequest类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#QNetworkReply类"><span class="nav-number">2.5.3.</span> <span class="nav-text">QNetworkReply类</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Mysql数据库表"><span class="nav-number">2.6.</span> <span class="nav-text">Mysql数据库表</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#MD5"><span class="nav-number">2.7.</span> <span class="nav-text">MD5</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#QT中使用MD5"><span class="nav-number">2.8.</span> <span class="nav-text">QT中使用MD5</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Base64"><span class="nav-number">2.9.</span> <span class="nav-text">Base64</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#QT中使用Base64"><span class="nav-number">2.10.</span> <span class="nav-text">QT中使用Base64</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#协议设计"><span class="nav-number">3.</span> <span class="nav-text">协议设计</span></a></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div>
<script async src="https//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<i class="fa fa-user-md"></i><span id="busuanzi_container_site_pv" style='display:none'>
    本站总访问量 <span id="busuanzi_value_site_pv"></span> 
    <span class="post-meta-divider">|</span>
</span>
<span id="busuanzi_container_site_uv" style='display:none'>
    访问人数 <span id="busuanzi_value_site_uv"></span>
</span>
</div>


<script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

<div class="copyright">&copy; 2018-8 &mdash; <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-"></i> Power by 
  </span>
  <span class="author" itemprop="copyrightHolder">zxp</span>
  
  
</div>









        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    
      <div id="needsharebutton-float">
        <span class="btn">
          <i class="fa fa-share-alt" aria-hidden="true"></i>
        </span>
      </div>
    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  




  
  <div id="lv-container" data-uid="MTAyMC8zODgxNC8xNTM0Mg==">
    <script type="text/javascript">
      (function(d, s) {
        var j, e = d.getElementsByTagName(s)[0];
        if (typeof LivereTower === 'function') { return; }
        j = d.createElement(s);
        j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
        j.async = true;
        e.parentNode.insertBefore(j, e);
      })(document, 'script');
    </script>
	</div>
  











  

  <script type="text/javascript">
    // Popup Window;
    var isfetched = false;
    var isXml = true;
    // Search DB path;
    var search_path = "search.xml";
    if (search_path.length === 0) {
      search_path = "search.xml";
    } else if (/json$/i.test(search_path)) {
      isXml = false;
    }
    var path = "/" + search_path;
    // monitor main search box;

    var onPopupClose = function (e) {
      $('.popup').hide();
      $('#local-search-input').val('');
      $('.search-result-list').remove();
      $('#no-result').remove();
      $(".local-search-pop-overlay").remove();
      $('body').css('overflow', '');
    }

    function proceedsearch() {
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay"></div>')
        .css('overflow', 'hidden');
      $('.search-popup-overlay').click(onPopupClose);
      $('.popup').toggle();
      var $localSearchInput = $('#local-search-input');
      $localSearchInput.attr("autocapitalize", "none");
      $localSearchInput.attr("autocorrect", "off");
      $localSearchInput.focus();
    }

    // search function;
    var searchFunc = function(path, search_id, content_id) {
      'use strict';

      // start loading animation
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay">' +
          '<div id="search-loading-icon">' +
          '<i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>' +
          '</div>' +
          '</div>')
        .css('overflow', 'hidden');
      $("#search-loading-icon").css('margin', '20% auto 0 auto').css('text-align', 'center');

      $.ajax({
        url: path,
        dataType: isXml ? "xml" : "json",
        async: true,
        success: function(res) {
          // get the contents from search data
          isfetched = true;
          $('.popup').detach().appendTo('.header-inner');
          var datas = isXml ? $("entry", res).map(function() {
            return {
              title: $("title", this).text(),
              content: $("content",this).text(),
              url: $("url" , this).text()
            };
          }).get() : res;
          var input = document.getElementById(search_id);
          var resultContent = document.getElementById(content_id);
          var inputEventFunction = function() {
            var searchText = input.value.trim().toLowerCase();
            var keywords = searchText.split(/[\s\-]+/);
            if (keywords.length > 1) {
              keywords.push(searchText);
            }
            var resultItems = [];
            if (searchText.length > 0) {
              // perform local searching
              datas.forEach(function(data) {
                var isMatch = false;
                var hitCount = 0;
                var searchTextCount = 0;
                var title = data.title.trim();
                var titleInLowerCase = title.toLowerCase();
                var content = data.content.trim().replace(/<[^>]+>/g,"");
                var contentInLowerCase = content.toLowerCase();
                var articleUrl = decodeURIComponent(data.url);
                var indexOfTitle = [];
                var indexOfContent = [];
                // only match articles with not empty titles
                if(title != '') {
                  keywords.forEach(function(keyword) {
                    function getIndexByWord(word, text, caseSensitive) {
                      var wordLen = word.length;
                      if (wordLen === 0) {
                        return [];
                      }
                      var startPosition = 0, position = [], index = [];
                      if (!caseSensitive) {
                        text = text.toLowerCase();
                        word = word.toLowerCase();
                      }
                      while ((position = text.indexOf(word, startPosition)) > -1) {
                        index.push({position: position, word: word});
                        startPosition = position + wordLen;
                      }
                      return index;
                    }

                    indexOfTitle = indexOfTitle.concat(getIndexByWord(keyword, titleInLowerCase, false));
                    indexOfContent = indexOfContent.concat(getIndexByWord(keyword, contentInLowerCase, false));
                  });
                  if (indexOfTitle.length > 0 || indexOfContent.length > 0) {
                    isMatch = true;
                    hitCount = indexOfTitle.length + indexOfContent.length;
                  }
                }

                // show search results

                if (isMatch) {
                  // sort index by position of keyword

                  [indexOfTitle, indexOfContent].forEach(function (index) {
                    index.sort(function (itemLeft, itemRight) {
                      if (itemRight.position !== itemLeft.position) {
                        return itemRight.position - itemLeft.position;
                      } else {
                        return itemLeft.word.length - itemRight.word.length;
                      }
                    });
                  });

                  // merge hits into slices

                  function mergeIntoSlice(text, start, end, index) {
                    var item = index[index.length - 1];
                    var position = item.position;
                    var word = item.word;
                    var hits = [];
                    var searchTextCountInSlice = 0;
                    while (position + word.length <= end && index.length != 0) {
                      if (word === searchText) {
                        searchTextCountInSlice++;
                      }
                      hits.push({position: position, length: word.length});
                      var wordEnd = position + word.length;

                      // move to next position of hit

                      index.pop();
                      while (index.length != 0) {
                        item = index[index.length - 1];
                        position = item.position;
                        word = item.word;
                        if (wordEnd > position) {
                          index.pop();
                        } else {
                          break;
                        }
                      }
                    }
                    searchTextCount += searchTextCountInSlice;
                    return {
                      hits: hits,
                      start: start,
                      end: end,
                      searchTextCount: searchTextCountInSlice
                    };
                  }

                  var slicesOfTitle = [];
                  if (indexOfTitle.length != 0) {
                    slicesOfTitle.push(mergeIntoSlice(title, 0, title.length, indexOfTitle));
                  }

                  var slicesOfContent = [];
                  while (indexOfContent.length != 0) {
                    var item = indexOfContent[indexOfContent.length - 1];
                    var position = item.position;
                    var word = item.word;
                    // cut out 100 characters
                    var start = position - 20;
                    var end = position + 80;
                    if(start < 0){
                      start = 0;
                    }
                    if (end < position + word.length) {
                      end = position + word.length;
                    }
                    if(end > content.length){
                      end = content.length;
                    }
                    slicesOfContent.push(mergeIntoSlice(content, start, end, indexOfContent));
                  }

                  // sort slices in content by search text's count and hits' count

                  slicesOfContent.sort(function (sliceLeft, sliceRight) {
                    if (sliceLeft.searchTextCount !== sliceRight.searchTextCount) {
                      return sliceRight.searchTextCount - sliceLeft.searchTextCount;
                    } else if (sliceLeft.hits.length !== sliceRight.hits.length) {
                      return sliceRight.hits.length - sliceLeft.hits.length;
                    } else {
                      return sliceLeft.start - sliceRight.start;
                    }
                  });

                  // select top N slices in content

                  var upperBound = parseInt('1');
                  if (upperBound >= 0) {
                    slicesOfContent = slicesOfContent.slice(0, upperBound);
                  }

                  // highlight title and content

                  function highlightKeyword(text, slice) {
                    var result = '';
                    var prevEnd = slice.start;
                    slice.hits.forEach(function (hit) {
                      result += text.substring(prevEnd, hit.position);
                      var end = hit.position + hit.length;
                      result += '<b class="search-keyword">' + text.substring(hit.position, end) + '</b>';
                      prevEnd = end;
                    });
                    result += text.substring(prevEnd, slice.end);
                    return result;
                  }

                  var resultItem = '';

                  if (slicesOfTitle.length != 0) {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + highlightKeyword(title, slicesOfTitle[0]) + "</a>";
                  } else {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + title + "</a>";
                  }

                  slicesOfContent.forEach(function (slice) {
                    resultItem += "<a href='" + articleUrl + "'>" +
                      "<p class=\"search-result\">" + highlightKeyword(content, slice) +
                      "...</p>" + "</a>";
                  });

                  resultItem += "</li>";
                  resultItems.push({
                    item: resultItem,
                    searchTextCount: searchTextCount,
                    hitCount: hitCount,
                    id: resultItems.length
                  });
                }
              })
            };
            if (keywords.length === 1 && keywords[0] === "") {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-search fa-5x" /></div>'
            } else if (resultItems.length === 0) {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>'
            } else {
              resultItems.sort(function (resultLeft, resultRight) {
                if (resultLeft.searchTextCount !== resultRight.searchTextCount) {
                  return resultRight.searchTextCount - resultLeft.searchTextCount;
                } else if (resultLeft.hitCount !== resultRight.hitCount) {
                  return resultRight.hitCount - resultLeft.hitCount;
                } else {
                  return resultRight.id - resultLeft.id;
                }
              });
              var searchResultList = '<ul class=\"search-result-list\">';
              resultItems.forEach(function (result) {
                searchResultList += result.item;
              })
              searchResultList += "</ul>";
              resultContent.innerHTML = searchResultList;
            }
          }

          if ('auto' === 'auto') {
            input.addEventListener('input', inputEventFunction);
          } else {
            $('.search-icon').click(inputEventFunction);
            input.addEventListener('keypress', function (event) {
              if (event.keyCode === 13) {
                inputEventFunction();
              }
            });
          }

          // remove loading animation
          $(".local-search-pop-overlay").remove();
          $('body').css('overflow', '');

          proceedsearch();
        }
      });
    }

    // handle and trigger popup window;
    $('.popup-trigger').click(function(e) {
      e.stopPropagation();
      if (isfetched === false) {
        searchFunc(path, 'local-search-input', 'local-search-result');
      } else {
        proceedsearch();
      };
    });

    $('.popup-btn-close').click(onPopupClose);
    $('.popup').click(function(e){
      e.stopPropagation();
    });
    $(document).on('keyup', function (event) {
      var shouldDismissSearchPopup = event.which === 27 &&
        $('.search-popup').is(':visible');
      if (shouldDismissSearchPopup) {
        onPopupClose();
      }
    });
  </script>





  

  
  <script src="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script>
  <script>AV.initialize("2AyV3DKioBSdoryrFLRohzjB-gzGzoHsz", "XynedcHyJCVCrTfbD4yYnodo");</script>
  <script>
    function showTime(Counter) {
      var query = new AV.Query(Counter);
      var entries = [];
      var $visitors = $(".leancloud_visitors");

      $visitors.each(function () {
        entries.push( $(this).attr("id").trim() );
      });

      query.containedIn('url', entries);
      query.find()
        .done(function (results) {
          var COUNT_CONTAINER_REF = '.leancloud-visitors-count';

          if (results.length === 0) {
            $visitors.find(COUNT_CONTAINER_REF).text(0);
            return;
          }

          for (var i = 0; i < results.length; i++) {
            var item = results[i];
            var url = item.get('url');
            var time = item.get('time');
            var element = document.getElementById(url);

            $(element).find(COUNT_CONTAINER_REF).text(time);
          }
          for(var i = 0; i < entries.length; i++) {
            var url = entries[i];
            var element = document.getElementById(url);
            var countSpan = $(element).find(COUNT_CONTAINER_REF);
            if( countSpan.text() == '') {
              countSpan.text(0);
            }
          }
        })
        .fail(function (object, error) {
          console.log("Error: " + error.code + " " + error.message);
        });
    }

    function addCount(Counter) {
      var $visitors = $(".leancloud_visitors");
      var url = $visitors.attr('id').trim();
      var title = $visitors.attr('data-flag-title').trim();
      var query = new AV.Query(Counter);

      query.equalTo("url", url);
      query.find({
        success: function(results) {
          if (results.length > 0) {
            var counter = results[0];
            counter.fetchWhenSave(true);
            counter.increment("time");
            counter.save(null, {
              success: function(counter) {
                var $element = $(document.getElementById(url));
                $element.find('.leancloud-visitors-count').text(counter.get('time'));
              },
              error: function(counter, error) {
                console.log('Failed to save Visitor num, with error message: ' + error.message);
              }
            });
          } else {
            var newcounter = new Counter();
            /* Set ACL */
            var acl = new AV.ACL();
            acl.setPublicReadAccess(true);
            acl.setPublicWriteAccess(true);
            newcounter.setACL(acl);
            /* End Set ACL */
            newcounter.set("title", title);
            newcounter.set("url", url);
            newcounter.set("time", 1);
            newcounter.save(null, {
              success: function(newcounter) {
                var $element = $(document.getElementById(url));
                $element.find('.leancloud-visitors-count').text(newcounter.get('time'));
              },
              error: function(newcounter, error) {
                console.log('Failed to create');
              }
            });
          }
        },
        error: function(error) {
          console.log('Error:' + error.code + " " + error.message);
        }
      });
    }

    $(function() {
      var Counter = AV.Object.extend("Counter");
      if ($('.leancloud_visitors').length == 1) {
        addCount(Counter);
      } else if ($('.post-title-link').length > 1) {
        showTime(Counter);
      }
    });
  </script>



  

  
<script>
(function(){
    var bp = document.createElement('script');
    var curProtocol = window.location.protocol.split(':')[0];
    if (curProtocol === 'https') {
        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';        
    }
    else {
        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
    }
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(bp, s);
})();
</script>


  
  
  
  <link rel="stylesheet" href="/lib/needsharebutton/needsharebutton.css">

  
  
  <script src="/lib/needsharebutton/needsharebutton.js"></script>

  <script>
    
      pbOptions = {};
      
          pbOptions.iconStyle = "default";
      
          pbOptions.boxForm = "vertical";
      
          pbOptions.position = "top";
      
          pbOptions.networks = "Weibo,Wechat,Douban,QQZone,Twitter,Facebook";
      
      new needShareButton('#needsharebutton-postbottom', pbOptions);
    
    
      flOptions = {};
      
          flOptions.iconStyle = "box";
      
          flOptions.boxForm = "horizontal";
      
          flOptions.position = "middleRight";
      
          flOptions.networks = "Weibo,Wechat,Douban,QQZone,Twitter,Facebook";
      
      new needShareButton('#needsharebutton-float', flOptions);
    
  </script>

  

  
  
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
        }
      });
    </script>

    <script type="text/x-mathjax-config">
      MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for (i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
        }
      });
    </script>
    <script type="text/javascript" src="//cdn.bootcss.com/mathjax/2.7.1/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
  


  
  <script type="text/javascript" src="/js/src/js.cookie.js?v=5.1.4"></script>
  <script type="text/javascript" src="/js/src/scroll-cookie.js?v=5.1.4"></script>


  
  <script type="text/javascript" src="/js/src/exturl.js?v=5.1.4"></script>


  
  
  	 <!-- custom analytics part create by xiamo -->
<script src="https://cdn1.lncld.net/static/js/av-core-mini-0.6.1.js"></script>
<script>AV.initialize("2AyV3DKioBSdoryrFLRohzjB-gzGzoHsz", "XynedcHyJCVCrTfbD4yYnodo");</script>
<script>
function showTime(Counter) {
	var query = new AV.Query(Counter);
	$(".leancloud_visitors").each(function() {
		var url = $(this).attr("id").trim();
		query.equalTo("url", url);
		query.find({
			success: function(results) {
				if (results.length == 0) {
					var content = $(document.getElementById(url)).text() + ' 0';
					$(document.getElementById(url)).text(content);
					return;
				}
				for (var i = 0; i < results.length; i++) {
					var object = results[i];
					var content = $(document.getElementById(url)).text() + ' ' + object.get('time');
					$(document.getElementById(url)).text(content);
				}
			}
		});

	});
}

</script>
  
</body>
</html>
